The FFI for this changed upstream. Instead of registering a single function that inputs a single buffer packed with all arguments, you now register a function for each method where there is a 1-1 mapping of arguments. The entire interface is represented by a "vtable" -- AKA a struct that has a field for each of the method handler functions To implement the methods, I stole the pattern we were using for regular calls where we define a base class that's implemented by normal code and a subclass that's implemented by generated code. Registering/deregistering callback interfaces is now handled by the generated code directly. It's simpler this way and now that we don't have the split between regular and fixture scaffolding, there's not much need for shared code to handle this. Kept the decision before to only support "fire-and-forget" callbacks. I think we will want to revisit this when the we support UniFFI async, but we can save that for later. Differential Revision: https://phabricator.services.mozilla.com/D222027
95 lines
3.6 KiB
C++
95 lines
3.6 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozilla_UniFFICallbacks_h
|
|
#define mozilla_UniFFICallbacks_h
|
|
|
|
#include "mozilla/StaticPtr.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
#include "mozilla/dom/UniFFIRust.h"
|
|
#include "mozilla/dom/UniFFIScaffolding.h"
|
|
|
|
namespace mozilla::uniffi {
|
|
|
|
/**
|
|
* Generated code to register a callback handler.
|
|
*
|
|
* This stores a reference to JS callback handler. When Rust wants to invoke a
|
|
* callback method, we will use this reference.
|
|
*
|
|
* Also, call the Rust FFI function to initialize the callback interface.
|
|
*/
|
|
void RegisterCallbackHandler(uint64_t aInterfaceId,
|
|
dom::UniFFICallbackHandler& aCallbackHandler,
|
|
ErrorResult& aError);
|
|
|
|
/**
|
|
* Generated code to deregister a callback handler.
|
|
*
|
|
* This releases the reference to the JS callback handler. After this, our
|
|
* vtable will still be registered with Rust, but all method calls will fail.
|
|
*/
|
|
void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError);
|
|
|
|
/**
|
|
* Implemented by generated code for each callback interface.
|
|
*
|
|
* The generated subclass handles the specifics of each call, while the code in
|
|
* the base class handles generic aspects of the call
|
|
*
|
|
* The generated subclass stores all data needed to make the call, including the
|
|
* arguments passed from Rust internally. MakeCall must only be called
|
|
* once-per-object, since it may consume some of the arguments. This means that
|
|
* we create a new UniffiCallbackMethodHandlerBase subclass instance for each
|
|
* callback interface call from Rust.
|
|
*/
|
|
class UniffiCallbackMethodHandlerBase {
|
|
protected:
|
|
// Name of the callback interface
|
|
const char* mInterfaceName;
|
|
uint64_t mObjectHandle;
|
|
|
|
// Invoke the callback method using a JS handler
|
|
MOZ_CAN_RUN_SCRIPT
|
|
virtual void MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler,
|
|
ErrorResult& aError) = 0;
|
|
|
|
public:
|
|
UniffiCallbackMethodHandlerBase(const char* aInterfaceName,
|
|
uint64_t aObjectHandle)
|
|
: mInterfaceName(aInterfaceName), mObjectHandle(aObjectHandle) {}
|
|
|
|
virtual ~UniffiCallbackMethodHandlerBase() = default;
|
|
|
|
// ---- Generic entry points ----
|
|
|
|
// Queue the method to be called asynchronously and ignore the return value.
|
|
//
|
|
// This is for fire-and-forget callbacks where the caller doesn't care about
|
|
// the return value and doesn't want to wait for the call to finish. A good
|
|
// use case for this is logging.
|
|
//
|
|
// FireAndForget is responsible for checking that the aJsHandler is non-null,
|
|
// this way we don't need to duplicate the null check in the generated code.
|
|
static void FireAndForget(
|
|
UniquePtr<UniffiCallbackMethodHandlerBase> aHandler,
|
|
StaticRefPtr<dom::UniFFICallbackHandler>* aJsHandler);
|
|
};
|
|
|
|
// Class to handle the free method, this is an implicit method for each callback
|
|
// interface. In inputs no arguments and has index=0.
|
|
class UniffiCallbackFreeHandler : public UniffiCallbackMethodHandlerBase {
|
|
public:
|
|
UniffiCallbackFreeHandler(const char* aInterfaceName, uint64_t aObjectHandle)
|
|
: UniffiCallbackMethodHandlerBase(aInterfaceName, aObjectHandle) {}
|
|
void MakeCall(JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler,
|
|
ErrorResult& aError) override;
|
|
};
|
|
|
|
} // namespace mozilla::uniffi
|
|
|
|
#endif // mozilla_UniFFICallbacks_h
|