File: Call.h

package info (click to toggle)
firefox 142.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,591,884 kB
  • sloc: cpp: 7,451,570; javascript: 6,392,463; ansic: 3,712,584; python: 1,388,569; xml: 629,223; asm: 426,919; java: 184,857; sh: 63,439; makefile: 19,150; objc: 13,059; perl: 12,983; yacc: 4,583; cs: 3,846; pascal: 3,352; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (177 lines) | stat: -rw-r--r-- 6,701 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* -*- 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_UniFFICall_h
#define mozilla_UniFFICall_h

#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/UniFFIBindingFwd.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/uniffi/OwnedRustBuffer.h"
#include "mozilla/uniffi/FfiValue.h"
#include "mozilla/uniffi/ResultPromise.h"
#include "mozilla/uniffi/Rust.h"

namespace mozilla::uniffi {

// Call Rust scaffolding functions
//
// This is the base of a class hierarchy for Rust call handling:
//   - UniffiCallHandlerBase contains the shared code for both async and sync
//   calls.
//   - UniffiSyncCallHandler and UniffiAsyncCallHandler contain generalized
//     code for sync/async calls
//   - The generated code creates subclasses one of the those and implements
//     the specialized code for the call.
//
// In all cases, a new instance is created each time the scaffolding function
// is called.
class UniffiCallHandlerBase {
 public:
  // Extract the call result when the status code is `RUST_CALL_SUCCESS`.
  //
  // On success, set aDest with the converted return value. If there is a
  // conversion error, set `aError`.  This can happen for example when a u64
  // value doesn't fit into a JS number.
  //
  // Called on the main thread.
  virtual void LiftSuccessfulCallResult(
      JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest,
      ErrorResult& aError) = 0;

  // Extract the result of making a call, and store it into aDest
  //
  // Errors are handled in several different ways:
  //   - If the Rust code returned an `Err` value, then `aDest.code` will be set
  //     to "error" and `aDest.data` will be set to the serialized error value.
  //   - If some other error happens in the Rust layer, then `aDest.code` will
  //     be set to "internal-error" and `aDest.data` will contain a serialized
  //     error string if possible and be empty otherwise.  This should be fairly
  //     rare, since the main case is a caught Rust panic, but FF sets
  //     panic=abort.
  //   - If some other error happens in the C++ layer, then `aError` will be set
  //     to the error.
  void LiftCallResult(
      JSContext* aCx,
      dom::RootedDictionary<dom::UniFFIScaffoldingCallResult>& aDest,
      ErrorResult& aError);

  virtual ~UniffiCallHandlerBase() = default;

 protected:
  // Call status from the rust call
  int8_t mUniffiCallStatusCode = RUST_CALL_SUCCESS;
  FfiValueRustBuffer mUniffiCallStatusErrorBuf;
};

// Call scaffolding functions for synchronous Rust calls
class UniffiSyncCallHandler : public UniffiCallHandlerBase {
 protected:
  // ---- Overridden by subclasses for each call ----

  // Convert a sequence of JS arguments and store them in this
  // UniffiSyncCallHandler. Called on the main thread.
  virtual void LowerRustArgs(
      const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
      ErrorResult& aError) = 0;

  // Call the underlying rust scaffolding function, using the arguments
  // stored in this UniffiHandler, and store the result as a member.
  // Potentially called on a background thread.
  //
  // aOutStatus is the out pointer passed to Rust.  The caller is responible
  // for using it to update `mUniffiCallStatusCode` and
  // `mUniffiCallStatusErrorBuf`.
  virtual void MakeRustCall(RustCallStatus* aOutStatus) = 0;

 public:
  virtual ~UniffiSyncCallHandler() = default;

  // ---- Generic entry points ----

  // Call the function synchronously
  static void CallSync(
      UniquePtr<UniffiSyncCallHandler> aHandler,
      const dom::GlobalObject& aGlobal,
      const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
      dom::RootedDictionary<dom::UniFFIScaffoldingCallResult>& aReturnValue,
      ErrorResult& aError);

  // Call the function asynchronously, in a worker queue.
  static already_AddRefed<dom::Promise> CallAsyncWrapper(
      UniquePtr<UniffiSyncCallHandler> aHandler,
      const dom::GlobalObject& aGlobal,
      const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
      ErrorResult& aError);
};

// Call scaffolding functions for asynchronous Rust calls
class UniffiAsyncCallHandler : public UniffiCallHandlerBase {
 public:
  UniffiAsyncCallHandler(PollFutureFn aPollFn, FreeFutureFn aFreeFn)
      : mPollFn(aPollFn), mFreeFn(aFreeFn) {}

 protected:
  // ---- Overridden by subclasses for each call ----

  // Convert a sequence of JS arguments and call the Rust scaffolding function.
  //
  // Always called on the main thread since async Rust calls don't block, they
  // return a future.  Because of this, there's no reason to split out the
  // `LowerRustArgs` and `MakeRustCall` like in the sync
  // case.
  virtual void LowerArgsAndMakeRustCall(
      const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
      ErrorResult& aError) = 0;

  // Handle to the future we're polling, set by MakeRustCall
  uint64_t mFutureHandle;
  // Rust future function pointers
  PollFutureFn mPollFn;
  FreeFutureFn mFreeFn;
  // Call the complete function.
  //
  // This can't be a function pointer like poll/free since the complete
  // function signature varies based on the return type.
  //
  // aOutStatus is the out pointer passed to Rust.  The caller is responible
  // for using it to update `mUniffiCallStatusCode` and
  // `mUniffiCallStatusErrorBuf`.
  virtual void CallCompleteFn(RustCallStatus* aOutStatus) = 0;

  // Call mPollFn to poll the future
  static void Poll(UniquePtr<UniffiAsyncCallHandler> aHandler);

 public:
  virtual ~UniffiAsyncCallHandler();

  // ---- Generic entry points ----

  // Call the function asynchronously
  static already_AddRefed<dom::Promise> CallAsync(
      UniquePtr<UniffiAsyncCallHandler> aHandler,
      const dom::GlobalObject& aGlobal,
      const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
      ErrorResult& aError);

 private:
  // Promise created by CallAsync
  ResultPromise mPromise;

  // Callback function for Rust async calls
  //
  // This is passed to Rust when we call the poll function.  The callback is
  // called when the future is ready or it's waker is invoked.  aCode is used to
  // distinguish the two cases.
  //
  // This is static so we can pass it as a function pointer to Rust.
  static void FutureCallback(uint64_t aCallHandlerHandle, int8_t aCode);
};

}  // namespace mozilla::uniffi

#endif  // mozilla_UniFFICall_h