How to write external function to call method invocation while compiling gleam code to JavaScript? - gleam

I am trying to write the Gleam JavaScript binding for basic DOM manipulation. I want to achieve following JavaScript functionality with gleam:
const div = document.createElement('div');
div.classList.add('className');
I am writing following external definition:
pub external type Document
pub external type HTMLElement
pub external fn create_elm(String) -> HTMLElement =
"" "document.createElement"
// HOW TO WRITE FOLLOWING EXTERNAL DEFINITION
pub external fn add_class(HTMLElement, String) -> Nil =
"" "$0.classList.add"
So, for add_class function, I want gleam to compile to JS such that first argument HTMLElement is used as a object and second argument String is passed to the some method of the HTMLElement. How to achieve this?
I could not find any documentation for this on gleam website. I thought something like the way Fable allows writing external binding would be possible. However, that doesn't work.

Gleam doesn't have any functionality for working with OOP JavaScript so in this case I would use some JavaScript glue code.
// in src/app.gleam
pub external type Document
pub external type HTMLElement
pub external fn create_elm(String) -> HTMLElement =
"" "document.createElement"
pub external fn add_class(HTMLElement, String) -> Nil =
"./app_ffi.mjs" "addClass"
// in src/app_ffi.mjs
export function(element, string) {
element.classList.add(string)
}

Related

Implementing a Windows Credential Provider

I recently discovered the windows-rs framework and have been looking to build a Windows Credential Provider in Rust by implementing their ICredentialProvider COM interface.
I've been working on a proof-of-concept implementation using the information put together under one of the existing issues, but I'm not sure how to actually expose the compiled rust as a proper DLL to then register with the windows system.
use std::cell::RefCell;
use windows::{
core::implement,
Win32::UI::Shell::{ICredentialProvider, ICredentialProvider_Impl},
};
fn main() -> windows::core::Result<()> {
#[implement(ICredentialProvider)]
struct Provider {
mutable_state: RefCell<u32>,
}
impl Provider {
fn new() -> Self {
Self {
mutable_state: RefCell::new(0),
}
}
}
impl ICredentialProvider_Impl for Provider {
fn Advise(
&self,
pcpe: &core::option::Option<windows::Win32::UI::Shell::ICredentialProviderEvents>,
upadvisecontext: usize,
) -> windows::core::Result<()> {
*self.mutable_state.borrow_mut() = 42;
todo!();
}
fn GetCredentialAt(
&self,
dwindex: u32,
) -> windows::core::Result<windows::Win32::UI::Shell::ICredentialProviderCredential>
{
todo!();
}
fn GetCredentialCount(
&self,
pdwcount: *mut u32,
pdwdefault: *mut u32,
pbautologonwithdefault: *mut windows::Win32::Foundation::BOOL,
) -> windows::core::Result<()> {
todo!();
}
fn GetFieldDescriptorAt(
&self,
dwindex: u32,
) -> windows::core::Result<
*mut windows::Win32::UI::Shell::CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR,
> {
todo!();
}
fn GetFieldDescriptorCount(&self) -> windows::core::Result<u32> {
todo!();
}
fn SetSerialization(
&self,
pcpcs: *const windows::Win32::UI::Shell::CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION,
) -> windows::core::Result<()> {
todo!();
}
fn SetUsageScenario(
&self,
cpus: windows::Win32::UI::Shell::CREDENTIAL_PROVIDER_USAGE_SCENARIO,
dwflags: u32,
) -> windows::core::Result<()> {
todo!();
}
fn UnAdvise(&self) -> windows::core::Result<()> {
todo!();
}
}
Ok(())
}
I compiled a Sample Credential Provider written in C++, supplied by Windows in their SDK, and used a tool to view the exported functions available in the generated DLL
There have been similar efforts in the windows-rs community to expose rust for WinRT but this COM interface needed for the Credential Provider is different enough I don't really know where to begin.
Are there any rust tricks to generate a similar DLL that can expose my interface and make it available to windows? Any help is appreciated.
A credential provider needs to be implemented as a COM server. A COM server is a PE image (EXE or DLL) that provides the following exports:
DllGetClassObject
DllCanUnloadNow1
DllGetClassObject is where the magic happens: It checks to see if the requested class (identified by rclsid) is implemented by the module, and subsequently returns a pointer to the requested interface riid (commonly an IClassFactory or IClassFactory2 interface). Once a client (the operating system, in case of a credential provider) received a class factory, it can use it to instantiate objects that implement interfaces such as the ICredentialProvider interface.
The key point here is that those two exports are all that's required for a module to be a COM server, that can expose arbitrary interfaces2.
That covers the systemic invariants. Moving into Rust the following issues need to be addressed:
Problem statement
Create a crate that produces a DLL
Instruct the linker to export symbols by a given name
Implement the interfaces
Implement the exported functions
Solution
First up, let's create a library crate. The following will do:
cargo new --lib cp_demo
Add this to Cargo.toml (removing anything beyond the [package] table):
[lib]
crate-type = ["cdylib"]
That addresses the first issue by having the crate produce a DLL. Running cargo build will produce cp_demo.dll inside targets/debug (assuming default settings). Mind you, this isn't making forward progress just yet. It merely creates a DLL that doesn't export anything (evidenced by running dumpbin /EXPORTS targets\debug\cp_demo.dll). It merely removes the obligation to have a fn main().
Having an "empty" DLL in place, we'll want to expose functionality to the outside world. The mechanics are very similar to the referenced resources, requiring a combination of an extern "system" block as well as the no_mangle attribute, so that the exports can be discovered by the system by name.
The former designates the calling convention, the contract between callers (the system) and callees (the implementation), formalizing how arguments are passed and who is responsible for (stack) cleanup on return. The latter instructs the linker to keep the exported symbols undecorated, so that the system can discover them by calling GetProcAddress(hmod, "DllGetClassObject"), for example.
Dumping the following into src/lib.rs
use std::{ffi, ptr};
use windows::{
core::{GUID, HRESULT},
Win32::Foundation::{CLASS_E_CLASSNOTAVAILABLE, E_POINTER, S_OK},
};
#[no_mangle]
extern "system" fn DllGetClassObject(
_rclsid: *const GUID,
_riid: *const GUID,
ppv: *mut *mut ffi::c_void,
) -> HRESULT {
// Implement basic COM contract
if ppv.is_null() {
E_POINTER
} else {
unsafe { *ppv = ptr::null_mut() };
CLASS_E_CLASSNOTAVAILABLE
}
}
#[no_mangle]
extern "system" fn DllCanUnloadNow() -> HRESULT {
// It's always safe to unload this module
S_OK
}
and updating Cargo.toml to include
[dependencies.windows]
version = "0.44.0"
features = [
"Win32_Foundation",
]
complies into a credential provider skeleton DLL. Running dumpbin /EXPORTS targets\debug\cp_demo.dll again produces output that includes
ordinal hint RVA name
1 0 00001080 DllCanUnloadNow = DllCanUnloadNow
2 1 00001000 DllGetClassObject = DllGetClassObject
Sweet! Now we have a credential provider that doesn't provide anything (and certainly not credentials). But it looks like a potential credential provider to the system already, that can be registered using the following .reg script (make sure to use a fresh GUID; this one won't be "globally unique" anymore by the time you're reading this).
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DED30376-B312-4168-B2D3-2D0B3EADE513}]
#="cp_demo"
[HKEY_CLASSES_ROOT\CLSID\{DED30376-B312-4168-B2D3-2D0B3EADE513}]
#="cp_demo"
[HKEY_CLASSES_ROOT\CLSID\{DED30376-B312-4168-B2D3-2D0B3EADE513}\InprocServer32]
#="cp_demo.dll"
"ThreadingModel"="Apartment"
The interface implementations follow the pattern you've already used in the question: Declare a custom type to hold local state (if any), apply the #[implement] attribute, and supply an implementation for the generated trait named <interface>_Impl.
For the ICredentialProvider interface3 this would roughly look like what is in the question. The only exception being that the following snippet replaces the todo!()'s with returning error codes, as it isn't legal for panics to cross the ABI4.
#[implement(ICredentialProvider)]
struct Provider {
_mutable_state: cell::RefCell<u32>,
}
impl Provider {
fn new() -> Self {
Self {
_mutable_state: cell::RefCell::new(0),
}
}
}
impl ICredentialProvider_Impl for Provider {
fn SetUsageScenario(
&self,
_cpus: CREDENTIAL_PROVIDER_USAGE_SCENARIO,
_dwflags: u32,
) -> Result<()> {
Err(E_NOTIMPL.into())
}
// ...
}
This isn't doing anything useful, other than failing gracefully in case the system manages to instantiate this implementation. To do this it needs an IClassFactory implementation that does:
#[implement(IClassFactory)]
struct ProviderFactory;
impl IClassFactory_Impl for ProviderFactory {
fn CreateInstance(
&self,
punkouter: &core::option::Option<windows::core::IUnknown>,
riid: *const windows::core::GUID,
ppvobject: *mut *mut core::ffi::c_void,
) -> windows::core::Result<()> {
// Validate arguments
if ppvobject.is_null() {
return Err(E_POINTER.into());
}
unsafe { *ppvobject = ptr::null_mut() };
if riid.is_null() {
return Err(E_INVALIDARG.into());
}
let riid = unsafe { *riid };
if punkouter.is_some() {
return Err(CLASS_E_NOAGGREGATION.into());
}
// We're only handling requests for `IID_ICredentialProvider`
if riid != ICredentialProvider::IID {
return Err(E_NOINTERFACE.into());
}
// Construct credential provider and return it as an `ICredentialProvider`
// interface
let provider: ICredentialProvider = Provider::new().into();
unsafe { *ppvobject = mem::transmute(provider) };
Ok(())
}
fn LockServer(&self, _flock: windows::Win32::Foundation::BOOL) -> windows::core::Result<()> {
Err(E_NOTIMPL.into())
}
}
This represents a fully functional class factory for an ICredentialProvider interface implemented by Provider. The better part of CreateInstance() consists of argument validation as mandated by the contract for IClassFactory::CreateInstance. The actual magic happens here:
let provider: ICredentialProvider = Provider::new().into();
This is doing a lot! Provider::new() is the obvious part: It instantiates a new Provider object. Not nearly as obvious is what the into() part does. It exercises the following From trait implementation that is ultimately generated by the #[implement] macro (cargo-expand is an indispensable tool for uncovering those hidden details):
impl ::core::convert::From<Provider> for ICredentialProvider {
fn from(this: Provider) -> Self {
let this = Provider_Impl::new(this);
let mut this = ::core::mem::ManuallyDrop::new(::std::boxed::Box::new(this));
let vtable_ptr = &this.vtables.0;
unsafe { ::core::mem::transmute(vtable_ptr) }
}
}
It takes a Provider instance, moves it into a (generated) Provider_Impl, then moves that into heap storage (Box::new()), wraps everything behind a ManuallyDrop, and finally transmutes the object pointer into the respective interface pointer.
Every bit of this is of crucial importance: Moving the Provider instance into heap memory makes sure that it remains valid across stack unwinding as part of function return, wrapping the Box inside a ManuallyDrop inhibits running the Drop implementation as the object falls out of scope (which would otherwise decrement the reference count to 0, destroying the object along the way), and returning an interface pointer allows the system to call into an unknown implementation through a known interface.
A corollary of the latter is that object cleanup is at the discretion of the implementation: When the reference count drops to 0, as clients call through Release(), it is the concrete implementation that frees resources (Provider_Impl::Release() specifically), irrespective of who the caller happens to be. Provider_Impl makes sure to match the allocation strategy used by the From trait implementation, so we don't have to worry about this detail.
A note on the LockServer implementation: It retuns E_NOTIMPL, mostly because I'm not confident to have understood it's purpose. This doesn't appear to have had any adverse effect while debugging, so I'm leaving it for now (more on this later).
With all that in place, we are in a good position to socialize: We have an ICredentialProvider implementation (Provider), that'll faithfully respond with E_NOTIMPL on every request, and an IClassFactory implementation (ProviderFactory), that'll dutifully procure as many of the aforementioned rascals as requested. What's missing in becoming BFF with the OS is to allow it to partake in our parenthood.
Detour on credential provider lookup and instantiation: Whenever the system needs to discover credential providers, it enumerates all values under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\ key in the registry. Each value's data names a UUID (generally referred to as a "GUID" in Windows programming) that identifies a credential provider implementation.
With a GUID identifying a COM interface implementation, what follows is rather generic COM infrastructure business. This applies to all of COM, not just credential providers. The (approximately accurate) algorithm is this:
Look up the GUID under the HKEY_CLASSES_ROOT\CLSID\ key. Its InprocServer32's data contains the (fully qualified) path to the implementing module.
Load the module and request an export called DllGetClassObject (the literal name is part of the contract, hence the #[no_mangle] attribute).
Request a class factory capable of instantiating a COM object identified by the given GUID (take note that GUID's are used to identify both COM interfaces as well as interface implementations, or "COM objects"; the former is generally spelled IID as in "interface ID", whereas the latter is referred to as CLSID as in "class ID").
Have the class factory create an instance.
That out of the way, it should be apparent why the .reg script above writes to two different keys, and also what's required to nudge the system into acknowledging this creation of our own: Step 3. above is the missing link, so let's fill that in:
#[no_mangle]
extern "system" fn DllGetClassObject(
rclsid: *const GUID,
riid: *const GUID,
ppv: *mut *mut ffi::c_void,
) -> HRESULT {
// The "class ID" this credential provider is identified by. This value needs to
// match the value used when registering the credential provider (see the .reg
// script above)
const CLSID_CP_DEMO: GUID = GUID::from_u128(0xDED30376_B312_4168_B2D3_2D0B3EADE513);
// Validate arguments
if ppv.is_null() {
return E_POINTER;
}
unsafe { *ppv = ptr::null_mut() };
if rclsid.is_null() || riid.is_null() {
return E_INVALIDARG;
}
let rclsid = unsafe { *rclsid };
let riid = unsafe { *riid };
// The following isn't strictly correct; a client *could* request an interface other
// than `IClassFactory::IID`, which this implementation is simply failing.
// This is safe, even if overly restrictive
if rclsid != CLSID_CP_DEMO || riid != IClassFactory::IID {
return CLASS_E_CLASSNOTAVAILABLE;
}
// Construct the factory object and return its `IClassFactory` interface
let factory: IClassFactory = ProviderFactory.into();
unsafe { *ppv = mem::transmute(factory) };
S_OK
}
#[no_mangle]
extern "system" fn DllCanUnloadNow() -> HRESULT {
// Since we aren't tracking module references (yet), it's never safe to unload this
// module
S_FALSE
}
This is following a familiar pattern: Most of DllGetClassObject() is argument validation, with let factory: IClassFactory = ProviderFactory.into(); doing the actual work.
The only difference here being that ProviderFactory is stateless (a "unit struct" in Rust parlance). It doesn't carry any information beyond it being a type. Which doesn't immediately appear to be useful, though it does allow us to implement traits on it (such as From). With ProviderFactory a unit struct expression we can call into() on it, kicking off the same machinery as described above, leaving use with a manually managed COM object living in heap memory so that we can return a pointer to it (*ppv = mem::transmute(factory)).
Note that the DllCanUnloadNow implementation changed from returning S_OK to S_FALSE. This isn't wrong as such, but it's also not what I'd like to do1. To address this we would need to record all references into this module, incrementing the reference count on every object creation, and decrementing it whenever objects implemented by this module get destroyed. I'm not entirely sure how to do that yet.
The final step closes the loop. With the above we can compile a credential provider DLL, allow the system to discover it and load the module, request a class factory from it, and have it create a credential provider. The credential provider doesn't do anything just yet; fleshing out the ICredentialProvider skeleton with functionality is for another update.
Debugging
TBD: VM and debugger setup
TBD: Test application
Dev experience
TBD: Add a build script that
generates a GUID on each build
generate Rust source to be used for CLSID_CP_DEMO
generate register.reg and unregister.reg files with matching GUIDs
1 This one doesn't strictly implement functionality; its purpose initially was to act as a performance optimization, allowing the implementing module to get unloaded when it's no longer needed. A conforming implementation could simply return S_FALSE unconditionally, and opt out of this optimization, though for a credential provider it's probably wise to allow the system to unload it as soon as possible. Keeping an attack surface into high value information around for longer than necessary ain't no smart move.
2 The actual interface methods do not need to be exported; they are returned to clients by way of arrays of function pointers.
3 A full implementation will also require us to provide an implementation of ICredentialProviderCredential, as that is returned from ICredentialProvider::GetCredentialAt.

Not sure how to use IDesktopWallpaper

In the documentation there is a struct 'IDesktopWallpaper' with a method named 'GetWallpaper'. The method takes a reference to 'self' but there is no constructor method for 'IDesktopWallpaper'.
use windows::{
core::*,
Win32::UI::Shell::IDesktopWallpaper,
};
fn main() -> Result<()> {
unsafe {
// ?????
IDesktopWallpaper::GetWallpaper(&self, monitorid);
}
Ok(())
}
What am I supposed to do in order to get my desired outcome?
COM generally uses factory methods to construct COM objects. The "standard" factory method for classic COM is CoCreateInstance. It needs a class ID that identifies the specific implementation (in case there are multiple) and an interface ID that names the requested interface.
The windows crate exposes class IDs differently from the Windows SDK: The latter frequently uses CLSID_-prefixes, wheres the former doesn't. DesktopWallpaper in the windows crate is the same GUID as CLSID_DesktopWallpaper in the Windows SDK.
Another difference is that CoCreateInstance in the windows crate is generic over its returned interface type (as opposed to taking the address of a type-erased void* in the Windows SDK). Clients will need to explicitly name the interface type they are requesting.
The following code initializes COM (required), instantiates a COM object, and returns an IDesktopWallpaper interface for further use:
use windows::{
core::Result,
Win32::{
System::Com::{CoCreateInstance, CoInitialize, CLSCTX_ALL},
UI::Shell::{DesktopWallpaper, IDesktopWallpaper},
},
};
fn main() -> Result<()> {
// Initialize COM
unsafe { CoInitialize(None) }?;
// Create a DesktkopWallpaper object and return its IDesktopWallpaper interface
let wallpaper: IDesktopWallpaper =
unsafe { CoCreateInstance(&DesktopWallpaper, None, CLSCTX_ALL) }?;
// Use the COM object
unsafe { wallpaper.GetWallpaper(...) };
Ok(())
}
You'll need to have the following in your Cargo.toml file:
[dependencies.windows]
version = "0.42.0"
features = [
"Win32_UI_Shell",
"Win32_System_Com",
]

How do you convert a Box<dyn Trait> to a Rc<dyn Trait>?

I have a function which receives a Box<dyn Trait> and needs to convert that into an Rc<dyn Trait> to share read-only ownership within the thread.
With a Box<T> of some T: Sized, we can do Rc::new(*my_box), but unfortunately that doesn't work for unsized trait objects.
Here's an oversimplified example which hopefully clarifies the problem:
use std::rc::Rc;
pub trait Trait {}
pub struct Foo {}
impl Trait for Foo {}
fn main() {
let trait_box: Box<dyn Trait> = Box::new(Foo {});
let trait_rc: Rc<dyn Trait> = Rc::new(*trait_box); // -> Error
}
Playground link
I saw some things here and there about exposing the internal RcBox to support moving between Box and Rc, but AFAIK it's not usable today.
Is there a workaround for this?
Or if this type of conversion isn't possible, what is the recommended method for storing a trait object which can be mutated up to a point, and then after that point be shared immutably with the rest of the program?
Using a Rc<RefCell<dyn Trait>> seems like overkill when I know I just have a single owner up to that point...
Rc<T> implements impl<T> From<Box<T, Global>> so you can just use into:
let trait_rc: Rc<dyn Trait> = trait_box.into();
Permalink to the playground

The trait bound io::Error: Clone is not satisfied when implementing a custom error enum

I am receiving the following error when implementing a custom error type:
the trait bound `std::io::Error: std::clone::Clone` is not satisfied
Here is my custom error enum:
use std::fmt;
use std::io;
use crate::memtable::Memtable;
// Define our error types. These may be customized for our error handling cases.
// Now we will be able to write our own errors, defer to an underlying error
// implementation, or do something in between.
#[derive(Debug, Clone)]
pub enum MemtableError {
Io(io::Error),
FromUTF8(std::string::FromUtf8Error),
NotFound,
}
// Generation of an error is completely separate from how it is displayed.
// There's no need to be concerned about cluttering complex logic with the display style.
//
// Note that we don't store any extra info about the errors. This means we can't state
// which string failed to parse without modifying our types to carry that information.
impl fmt::Display for MemtableError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Some error occurred!");
Ok(())
}
}
// a test function that returns our error result
fn raises_my_error(memtable: Memtable, key: String) -> Result<(),MemtableError> {
match memtable.read(key) {
Ok(v) => Ok(()),
Err(e) => Err(e),
}
}
What am I doing wrong? I tried following these examples:
https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/define_error_type.html
https://learning-rust.github.io/docs/e7.custom_error_types.html
https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/wrap_error.html
In your MemtableError-enum you use std::io::error which does not implement Clone. That's what the error message is saying. You should also get the same error about std::string::FromUtf8Error.
To solve this issue you can either remove Clone from your derive-macro. Or you need to explicitly implement Clone on your error-type. This however wont work in the current setup, because io::Error uses a trait object (Box<dyn Error + Send + Sync>) internally. And this trait object cannot be cloned. See this issue. A workaround would be to put std::io::Error and std::string::FromUtf8Error in a Rc or Arc:
#[derive(Debug, Clone)]
pub enum MemtableError {
Io(std::rc::Rc<io::Error>),
FromUTF8(std::rc::Rc<std::string::FromUtf8Error>),
NotFound,
}
To see if this is a reasonable way to solve this issue we need to know more about the rest of your code.
So, the easiest fix is to remove Clone. Otherwise work with Rc/Arc.
The error occurs because you're attempting to derive a Clone implementation for MemtableError, but std::io::Error (the type of one of the values that your MemtableError can store) doesn't implement Clone itself. If cloning isn't required, I'd change it to simply be #[derive(Debug)]. Otherwise, we'll need more context on your use case to suggest a more specific fix.

Function as argument, access inner parameter

The package valyala/fasthttp implements the following function type:
type RequestHandler func(ctx *RequestCtx)
It is used in buaazp/fasthttprouter like this:
func (r *Router) Handle(method, path string, handle fasthttp.RequestHandler) {
//...
}
I am trying to wrap these like this (open for suggestions on implementation):
//myapp/router
type Request struct {
fasthttp.RequestCtx
}
type RequestHandler func(*Request)
func Handle(method string, path string, handler RequestHandler) {
//I need to access the fasthttp.RequestCtx stuff in here...
}
How can I achieve this? Or, if this is not the way to go at all, how can I achieve my goal as mentioned below for a router package?
BACKGROUND
Goal: My wish is to wrap tooling packages (sessions, database, routing, etc.) in order to make my app agnostic to the implementation of these packages. I wish to do this primarily for the purpose of being able to extend these with domain-specific functionality, and being able to switch one 3rd party lib for another, if I ever would need to do so. It also makes debugging and logging easier.
Method: I create native types and functions, which map to the functionality of the imported packages.
Problem: I am stuck on how to wrap a foreign (i.e. imported) function type properly.
At all your idea looks very good. Some things you could change:
//myapp/router
// Using a composition is idiomatic go code
// this should work. It can't get better.
type Request struct {
fasthttp.RequestCtx
}
// I would make the RequestHandler as a real Handler. In go it would be
// a interface
type RequestHandler interface{
Request(*Request)
}
// If you have a function, which needs to access parameters from `Request`
// you should take this as an input.
func Handle(method string, path string, req *Request) {
//Access Request via req.Request ...
}
Because if you pass a function or an interface into your function, which needs also Request as input the caller needs to create that before he calls your Handle function. Why not change that function just for the input you really need?

Resources