 f9b53c8833
			
		
	
	
		f9b53c8833
		
	
	
	
	
		
			
			Added documents on how things work internally. Also updated the "Developing Rust Components" section. Added info on threading issues and removed info covered by the internals docs. Differential Revision: https://phabricator.services.mozilla.com/D252244
		
			
				
	
	
	
	
		
			3 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	JavaScript Callback Interfaces
Background
JavaScript layer
The generated JavaScript bindings create a UniFFICallbackHandler for each callback interface. This stores the callback interface implementations that are manually written by Firefox engineers. These are stored in a map, where the key is an integer handle for the callback interface.
UniFFICallbackHandler.callAsync is used by the C++ layer to invoke callback interface methods.
See below for why we only currently have callAsync().
UniFFICallbackHandler.callAsync() inputs:
- The object handle
- The method index
- Each argument for the callback method, after being lowered by JavaScript.
UniFFICallbackHandler.callAsync() returns a UniFFIScaffoldingCallResult.
Like with Rust calls, this is a UniffiCallStatus combined with a return value.
For each callback interface, the JavaScript layer calls UniFFIScaffolding.registerCallbackHandler() with the UniFFICallbackHandler for that interface.
Like with Rust calls, the bindings code generates a unique ID to identify each callback interface.
C++ layer
The C++ layer acts as a bridge between the generated Rust code and the generated JavaScript code. It registers a vtable with the Rust code where each field points to a generated C function that:
- Looks up the UniFFICallbackHandlerregistered withUniFFIScaffolding.registerCallbackHandler()
- Lifts all passed arguments and passes them to the UniFFICallbackHandler.
- For fire-and-forget calls:
- Calls UniFFICallbackHandler.callAsync()with the lifted arguments then discards the returned Promise.
- Note: sync calls are currently always wrapped to be "fire-and-forget" callbacks
 
- Calls 
- For async calls:
- Calls UniFFICallbackHandler.callAsync()with the lifted arguments getting back a Promise object.
- Appends a PromiseNativeHandler to promise object.
- The PromiseNativeHandlercompletes the promise by calling the complete callback as described in the UniFFI FFI internals doc.
- The PromiseNativeHandleralso has code to handle a rejected promise by calling the complete callback withRustCallStatusCode::UnexpectedError.
 
- Calls 
Freeing Callback Interface Objects
Each VTable also has a uniffi_free method.
When the Rust code drops the callback interface object, the generated UniFFI code arranges for uniffi_free to be called.
When this happens, the C++ generated function calls UniFFICallbackHandler.destroy().
The generated JavaScript handles that by removing the entry from the callback interface map.