oc_wasm_safe/component.rs
1//! Types related to examining and calling methods on components attached to or installed in a
2//! computer.
3//!
4//! Some of the APIs in this module are independent and can be used standalone. Invoking methods,
5//! however, is more complicated, and must be done as follows:
6//!
7//! 1. Call [`Invoker::take`] if not already done (this can only be done once at program startup)
8//! to obtain an [`Invoker`].
9//! 2. Call one of the methods on the [`Invoker`] to start the component call. On success, this
10//! returns an [`InvokeResult`] indicating whether the call is complete or not along with a
11//! [`MethodCall`] to use to fetch the result.
12//! 3. If necessary, wait until the call is complete by returning from `run`.
13//! 4. If necessary, call [`MethodCall::end_length`] to allocate a sufficient buffer to hold the
14//! result.
15//! 5. Call one of the methods on [`MethodCall`] to fetch the result, which both fills the provided
16//! buffer and also returns an [`InvokeEndResult`].
17//! 6. If [`Done`](InvokeEndResult::Done) is returned with an `Ok` result, examine the result in
18//! the buffer.
19//! 7. If [`Done`](InvokeEndResult::Done) is returned with an `Err` result, the
20//! [`MethodCallError`] can be examined to determine the reason for the failure, including
21//! detailed exception information in the form of a [`LastException`] object if applicable.
22//! 8. Another method call can only be started once the [`InvokeResult`], [`MethodCall`],
23//! [`InvokeEndResult`], and [`LastException`] have all been dropped. This is enforced by means
24//! of lifetime bindings between those types and the [`Invoker`], preventing the latter from
25//! being reused too early.
26
27use super::descriptor::AsDescriptor;
28use super::error::{Error, Result};
29use super::helpers::{call_buffer_len, call_buffer_str, call_string};
30use super::Address;
31use crate::panic_or_trap;
32use core::convert::TryFrom;
33use core::fmt::{Display, Formatter};
34use core::marker::PhantomData;
35use core::num::NonZeroUsize;
36use core::ptr;
37use core::sync::atomic::{AtomicBool, Ordering};
38use oc_wasm_sys::component as sys;
39
40/// An object that is capable of listing components attached to the computer.
41///
42/// Because only one component listing can be in progress at a time, only one value of this type
43/// can exist. An application written as a state machine should take the instance and store it in a
44/// `static` variable. An application using `async` and `await` in which only one task needs to
45/// list components should either take the value in that task, or take it in the top-level task and
46/// move it into the task that needs it. An application using `async` and `await` in which multiple
47/// tasks all need to list components needs to arrange mutual exclusion so that only one task can
48/// access the lister at a time.
49pub struct Lister(());
50
51impl Lister {
52 /// Returns the lister.
53 ///
54 /// This function can only be called once in the lifetime of the application. On the second and
55 /// subsequent calls, it will return `None`.
56 #[must_use = "A Lister can only be taken once. It needs to be saved. Discarding it means it is impossible to ever list components."]
57 pub fn take() -> Option<Self> {
58 static TAKEN: AtomicBool = AtomicBool::new(false);
59 if TAKEN.swap(true, Ordering::Relaxed) {
60 None
61 } else {
62 Some(Self(()))
63 }
64 }
65
66 /// Begins listing the components attached to the computer.
67 ///
68 /// The `component_type` parameter, if present, restricts the listing to only return components
69 /// of the specified type. If the parameter is absent, all components are returned.
70 ///
71 /// # Panics
72 /// This function panics if the underlying syscall fails, because the only reasons it could
73 /// fail should be impossible due to the type system.
74 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
75 pub fn start<'lister>(&'lister mut self, component_type: Option<&str>) -> Listing<'lister> {
76 let result =
77 // SAFETY: list_start permits null or a string pointer/length pair.
78 unsafe{call_string(sys::list_start, component_type)};
79 // Can’t fail because list_start can only fail due to MemoryFault or StringDecode, and
80 // Error::from_i32 already treats those as unreachable.
81 result.unwrap_or_else(|_| panic_or_trap!("unreachable"));
82 Listing(PhantomData)
83 }
84}
85
86/// An in-progress component listing.
87///
88/// The `'lister` lifetime parameter is the lifetime of the component lister that is performing the
89/// listing.
90#[must_use = "Starting a component listing is only useful if you read the results."]
91pub struct Listing<'lister>(PhantomData<&'lister mut Lister>);
92
93impl<'lister> Listing<'lister> {
94 /// Returns the next entry in the list of components.
95 ///
96 /// If there is a next entry, its UUID is return. If not, `None` is returned.
97 ///
98 /// # Panics
99 /// * This function panics if the underlying syscall fails, because the only reasons it could
100 /// fail should be impossible due to the type system.
101 /// * This function panics if there is a mismatch between OC-Wasm-safe’s and OpenComputers’s
102 /// ideas of the length or formatting of a component address.
103 #[allow(clippy::should_implement_trait)] // It’s very like Iterator::next, but can’t be due to lifetimes.
104 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
105 pub fn next<'listing>(&'listing mut self) -> Option<ListEntry<'listing, 'lister>> {
106 // SAFETY: list_next permits a writeable buffer pointer and promises to always write a
107 // valid UUID. It can only fail due to MemoryFault, which, because we provide it with a
108 // valid buffer, is impossible. However we care whether its return value is 0 or 1.
109 let mut buf = uuid::Bytes::default();
110 let rc = unsafe { sys::list_next(buf.as_mut_ptr()) };
111 if rc == 0 {
112 None
113 } else {
114 let address = Address::from_bytes(buf);
115 Some(ListEntry {
116 address,
117 listing: PhantomData,
118 })
119 }
120 }
121}
122
123/// A single in from a listing.
124///
125/// The `'lister` lifetime parameter is the lifetime of the component lister. The `'listing`
126/// lifetime parameter is the lifetime of the specific listing being performed.
127#[derive(Debug)]
128pub struct ListEntry<'listing, 'lister> {
129 /// The component address.
130 address: Address,
131
132 /// A phantom that allows the `'listing` lifetime to be recorded.
133 listing: PhantomData<&'listing mut Listing<'lister>>,
134}
135
136impl ListEntry<'_, '_> {
137 /// Returns the address of the component.
138 #[must_use = "This function is only useful for its return value"]
139 pub fn address(&self) -> &Address {
140 &self.address
141 }
142
143 /// Returns the length, in bytes, of the component’s type.
144 ///
145 /// # Panics
146 /// * This function panics if the underlying syscall fails, because the only reasons it could
147 /// fail should be impossible due to the type system.
148 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
149 #[must_use = "This function is only useful for its return value"]
150 pub fn type_name_len(&self) -> NonZeroUsize {
151 // SAFETY: list_type permits null.
152 let len = unsafe { call_buffer_len(sys::list_type) }
153 .unwrap_or_else(|_| panic_or_trap!("unreachable"));
154 // SAFETY: A component type can’t be empty.
155 unsafe { NonZeroUsize::new_unchecked(len) }
156 }
157
158 /// Returns the type of the most recently listed component.
159 ///
160 /// The `buffer` parameter identifies where to store the component type.
161 ///
162 /// The type is written to `buffer` and a string slice referring to it is returned.
163 ///
164 /// # Errors
165 /// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is provided but is not
166 /// large enough to hold the component type.
167 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
168 #[must_use = "This function is only useful for its return value"]
169 pub fn type_name<'buffer>(&self, buffer: &'buffer mut [u8]) -> Result<&'buffer mut str> {
170 // SAFETY: list_type permits a writeable buffer pointer/length pair and promises to always
171 // write a valid UTF-8 string and return its length.
172 unsafe { call_buffer_str(sys::list_type, buffer) }
173 }
174}
175
176/// Returns the length, in bytes, of the type of a component.
177///
178/// The `address` parameter identifies the component by its UUID.
179///
180/// # Errors
181/// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist or is
182/// inaccessible.
183#[allow(clippy::module_name_repetitions)] // For parallelism with component_type
184#[must_use = "This function is only useful for its return value"]
185pub fn component_type_len(address: &Address) -> Result<NonZeroUsize> {
186 let address = address.as_bytes();
187 let len = Error::from_isize(
188 // SAFETY: component_type permits a UUID input pointer and null output pointer/length pair.
189 unsafe { sys::component_type(address.as_ptr(), ptr::null_mut(), 0) },
190 )?;
191 // SAFETY: A component type can’t be empty.
192 Ok(unsafe { NonZeroUsize::new_unchecked(len) })
193}
194
195/// Returns the type of a component.
196///
197/// The `address` parameter identifies the component by its UUID. The `buffer` parameter identifies
198/// where to store the component type.
199///
200/// The type is written into `buffer` and a string slice referring to it is returned.
201///
202/// # Errors
203/// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is provided but is not
204/// large enough to hold the component type.
205/// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist or is
206/// inaccessible.
207#[allow(clippy::module_name_repetitions)] // Because just “type” would be a keyword
208#[must_use = "This function is only useful for its return value"]
209pub fn component_type<'buf>(address: &Address, buffer: &'buf mut [u8]) -> Result<&'buf mut str> {
210 let address = address.as_bytes();
211 let bytes_written = {
212 let buf_len = buffer.len();
213 let buf_ptr = buffer.as_mut_ptr();
214 Error::from_isize(
215 // SAFETY: component_type permits a UUID input pointer and a writeable buffer output
216 // pointer/length pair.
217 unsafe { sys::component_type(address.as_ptr(), buf_ptr, buf_len) },
218 )?
219 };
220 Ok(
221 // SAFETY: component_type promises to always write a valid UTF-8 string and return its
222 // length.
223 unsafe { core::str::from_utf8_unchecked_mut(buffer.get_unchecked_mut(0..bytes_written)) },
224 )
225}
226
227/// Returns the slot that a component is installed into.
228///
229/// The `address` parameter identifies the component by its UUID.
230///
231/// # Errors
232/// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist or is
233/// inaccessible.
234/// * [`Other`](Error::Other) is returned if the component exists but is not installed in a slot.
235#[must_use = "This function is only useful for its return value"]
236pub fn slot(address: &Address) -> Result<u32> {
237 let address = address.as_bytes();
238 Error::from_i32(
239 // SAFETY: slot permits a UUID input pointer.
240 unsafe { sys::slot(address.as_ptr()) },
241 )
242}
243
244/// An object that is capable of listing methods on a component or opaque value.
245///
246/// Because only one method listing can be in progress at a time, only one value of this type can
247/// exist. An application written as a state machine should take the instance and store it in a
248/// `static` variable. An application using `async` and `await` in which only one task needs to
249/// list methods should either take the value in that task, or take it in the top-level task and
250/// move it into the task that needs it. An application using `async` and `await` in which multiple
251/// tasks all need to list methods needs to arrange mutual exclusion so that only one task can
252/// access the lister at a time.
253pub struct MethodLister(());
254
255impl MethodLister {
256 /// Returns the lister.
257 ///
258 /// This function can only be called once in the lifetime of the application. On the second and
259 /// subsequent calls, it will return `None`.
260 #[must_use = "A Lister can only be taken once. It needs to be saved. Discarding it means it is impossible to ever list methods."]
261 pub fn take() -> Option<Self> {
262 static TAKEN: AtomicBool = AtomicBool::new(false);
263 if TAKEN.swap(true, Ordering::Relaxed) {
264 None
265 } else {
266 Some(Self(()))
267 }
268 }
269
270 /// Begins iteration over the methods available on a component.
271 ///
272 /// The `address` parameter identifies the component by its UUID.
273 ///
274 /// # Errors
275 /// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist
276 /// or is inaccessible.
277 #[allow(clippy::module_name_repetitions)] // Important to distinguish from methods_start_value
278 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
279 pub fn start_component<'lister>(
280 &'lister mut self,
281 address: &Address,
282 ) -> Result<MethodListing<'lister>> {
283 let address = address.as_bytes();
284 // SAFETY: methods_start_component permits an input UUID pointer.
285 Error::from_i32(unsafe { sys::methods_start_component(address.as_ptr()) })?;
286 Ok(MethodListing(PhantomData))
287 }
288
289 /// Begins iteration over the methods available on an opaque value.
290 ///
291 /// The `descriptor` parameter identifies the opaque value by its descriptor.
292 ///
293 /// Iteration over methods is not reentrant. Concurrent software must ensure that only one method
294 /// iteration at a time is attempted. This is even true if different components are involved, or if
295 /// one is over a component and the other over an opaque value.
296 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
297 pub fn start_value(&mut self, descriptor: &impl AsDescriptor) -> MethodListing<'_> {
298 // SAFETY: methods_start_value permits a descriptor.
299 // SOUNDNESS: Ignoring the return value is sound because methods_start_value can only fail
300 // due to BadDescriptor, and BadDescriptor cannot happen because the parameter is a
301 // Descriptor object.
302 unsafe { sys::methods_start_value(descriptor.as_descriptor().as_raw()) };
303 MethodListing(PhantomData)
304 }
305}
306
307/// The possible attributes of a method.
308#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
309pub struct MethodAttributes {
310 /// The method is direct.
311 ///
312 /// If this value is `true`, the method can be called and completed within a single timeslice.
313 /// The caller cannot assume that every invocation of a direct method will complete within a
314 /// timeslice, as even direct calls may have call budget limits; however, if this value is
315 /// `false`, then no call to the method will ever complete immediately.
316 pub direct: bool,
317
318 /// The method is a property getter.
319 ///
320 /// If this value is `true`, the method conceptually reads the value of a property, rather than
321 /// performing an action.
322 pub getter: bool,
323
324 /// The method is a property setter.
325 ///
326 /// If this value is `true`, the method conceptually writes the value of a property, rather
327 /// than performing an action.
328 pub setter: bool,
329}
330
331impl From<u32> for MethodAttributes {
332 fn from(value: u32) -> Self {
333 Self {
334 direct: (value & 1) != 0,
335 getter: (value & 2) != 0,
336 setter: (value & 4) != 0,
337 }
338 }
339}
340
341#[must_use = "Starting a method listing is only useful if you read the results."]
342pub struct MethodListing<'lister>(PhantomData<&'lister mut MethodLister>);
343
344impl MethodListing<'_> {
345 /// Returns the length, in bytes, of the name of the next method in the list of methods.
346 ///
347 /// If there is no next entry, `None` is returned.
348 ///
349 /// # Panics
350 /// This function panics if the underlying syscall fails, because the only reasons it could
351 /// fail should be impossible due to the type system.
352 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
353 #[must_use = "This function is only useful for its return value"]
354 pub fn next_len(&self) -> Option<NonZeroUsize> {
355 let result = Error::from_isize(
356 // SAFETY: methods_next permits null for both pointers.
357 unsafe { sys::methods_next(ptr::null_mut(), 0, ptr::null_mut()) },
358 );
359 // Can’t fail because methods_next can only fail due to MemoryFault or StringDecode, and
360 // Error::from_isize already treats those as unreachable.
361 NonZeroUsize::new(result.unwrap_or_else(|_| panic_or_trap!("unreachable")))
362 }
363
364 /// Returns the next method in the list of methods.
365 ///
366 /// The `buffer` parameter identifies where to store the next method name.
367 ///
368 /// If there is a next method, its name is written to `buffer`, a string slice referring to the
369 /// name along with the attributes are returned, and the iteration is advanced. If not, `None`
370 /// is returned.
371 ///
372 /// # Errors
373 /// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is not large enough to
374 /// hold the method name.
375 ///
376 /// On error, the iteration does not advance.
377 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
378 pub fn next<'buffer>(
379 &mut self,
380 buffer: &'buffer mut [u8],
381 ) -> Result<Option<(&'buffer mut str, MethodAttributes)>> {
382 let mut attributes = 0_u32;
383 let bytes_written = {
384 let len = buffer.len();
385 let ptr = buffer.as_mut_ptr();
386 Error::from_isize(
387 // SAFETY: methods_next permits a writeable buffer pointer/length pair and a pointer to
388 // a single i32 attributes bitmask.
389 unsafe { sys::methods_next(ptr, len, &mut attributes) },
390 )?
391 };
392 if bytes_written == 0 {
393 Ok(None)
394 } else {
395 Ok(Some((
396 // SAFETY: methods_next promises to always write a valid UTF-8 string and return its
397 // length.
398 unsafe {
399 core::str::from_utf8_unchecked_mut(buffer.get_unchecked_mut(0..bytes_written))
400 },
401 attributes.into(),
402 )))
403 }
404 }
405}
406
407/// Returns the length, in bytes, of the documentation for a method on a component.
408///
409/// The `address` parameter identifies the component by its UUID. The `method` parameter identifies
410/// the method by its name.
411///
412/// # Errors
413/// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist or is
414/// inaccessible.
415/// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method does not exist on the
416/// component.
417#[must_use = "This function is only useful for its return value"]
418pub fn documentation_component_length(address: &Address, method: &str) -> Result<usize> {
419 let address = address.as_bytes();
420 Error::from_isize(
421 // SAFETY: documentation_component permits an input address UUID pointer and method name
422 // string pointer/length pair, and a null output pointer/length pair.
423 unsafe {
424 sys::documentation_component(
425 address.as_ptr(),
426 method.as_ptr(),
427 method.len(),
428 ptr::null_mut(),
429 0,
430 )
431 },
432 )
433}
434
435/// Returns the documentation for a method on a component.
436///
437/// The `address` parameter identifies the component by its UUID. The `method` parameter identifies
438/// the method by its name. The `buffer` parameter identifies where to store the documentation.
439///
440/// The documentation is written into `buffer` and a string slice referring to it is returned.
441///
442/// # Errors
443/// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is provided but is not
444/// large enough to hold the documentation.
445/// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the component does not exist or is
446/// inaccessible.
447/// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method does not exist on the
448/// component.
449#[allow(clippy::module_name_repetitions)] // Important to distinguish from documentation_value
450#[must_use = "This function is only useful for its return value"]
451pub fn documentation_component<'buf>(
452 address: &Address,
453 method: &str,
454 buffer: &'buf mut [u8],
455) -> Result<&'buf mut str> {
456 let address = address.as_bytes();
457 let bytes_written = {
458 let buf_len = buffer.len();
459 let buf_ptr = buffer.as_mut_ptr();
460 Error::from_isize(
461 // SAFETY: documentation_component permits an input address UUID pointer and method name
462 // string pointer/length pair, and a writeable buffer output pointer/length pair.
463 unsafe {
464 sys::documentation_component(
465 address.as_ptr(),
466 method.as_ptr(),
467 method.len(),
468 buf_ptr,
469 buf_len,
470 )
471 },
472 )?
473 };
474 Ok(
475 // SAFETY: documentation_component promises to always write a valid UTF-8 string and return
476 // its length.
477 unsafe { core::str::from_utf8_unchecked_mut(buffer.get_unchecked_mut(0..bytes_written)) },
478 )
479}
480
481/// Returns the length, in bytes, of the documentation for a method on a value.
482///
483/// The `descriptor` parameter identifies the value by its descriptor. The `method` parameter
484/// identifies the method by its name.
485///
486/// # Errors
487/// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method does not exist on the
488/// value.
489#[must_use = "This function is only useful for its return value"]
490pub fn documentation_value_length(descriptor: &impl AsDescriptor, method: &str) -> Result<usize> {
491 Error::from_isize(
492 // SAFETY: documentation_value permits two string pointer/length pairs and a null.
493 unsafe {
494 sys::documentation_value(
495 descriptor.as_descriptor().as_raw(),
496 method.as_ptr(),
497 method.len(),
498 ptr::null_mut(),
499 0,
500 )
501 },
502 )
503}
504
505/// Returns the documentation for a method on a value.
506///
507/// The `descriptor` parameter identifies the value by its descriptor. The `method` parameter
508/// identifies the method by its name. The `buffer` parameter identifies where to store the
509/// documentation.
510///
511/// The documentation is written into `buffer` and a string slice referring to it is returned.
512///
513/// # Errors
514/// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is provided but is not
515/// large enough to hold the documentation.
516/// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method does not exist on the value.
517#[must_use = "This function is only useful for its return value"]
518pub fn documentation_value<'buf>(
519 descriptor: &impl AsDescriptor,
520 method: &str,
521 buffer: &'buf mut [u8],
522) -> Result<&'buf mut str> {
523 let bytes_written = {
524 let buf_len = buffer.len();
525 let buf_ptr = buffer.as_mut_ptr();
526 Error::from_isize(
527 // SAFETY: documentation_value permits two string pointer/length pairs and a writeable
528 // buffer pointer/length pair.
529 unsafe {
530 sys::documentation_value(
531 descriptor.as_descriptor().as_raw(),
532 method.as_ptr(),
533 method.len(),
534 buf_ptr,
535 buf_len,
536 )
537 },
538 )?
539 };
540 Ok(
541 // SAFETY: documentation_value promises to always write a valid UTF-8 string and return its
542 // length.
543 unsafe { core::str::from_utf8_unchecked_mut(buffer.get_unchecked_mut(0..bytes_written)) },
544 )
545}
546
547/// An object that is capable of invoking methods.
548///
549/// Because only one method can be invoked at a time, only one value of this type can exist. An
550/// application written as a state machine should take the instance and store it in a `static`
551/// variable. An application using `async` and `await` in which only one task needs to make method
552/// calls should either take the value in that task, or take it in the top-level task and move it
553/// into the task that needs it. An application using `async` and `await` in which multiple tasks
554/// all need to make method calls needs to arrange mutual exclusion so that only one task can
555/// access the invoker at a time.
556pub struct Invoker(());
557
558impl Invoker {
559 /// Returns the invoker.
560 ///
561 /// This function can only be called once in the lifetime of the application. On the second and
562 /// subsequent calls, it will return `None`.
563 #[must_use = "An Invoker can only be taken once. It needs to be saved. Discarding it means it is impossible to ever make a method call."]
564 pub fn take() -> Option<Self> {
565 static TAKEN: AtomicBool = AtomicBool::new(false);
566 if TAKEN.swap(true, Ordering::Relaxed) {
567 None
568 } else {
569 Some(Self(()))
570 }
571 }
572
573 /// Starts invoking a method on a component.
574 ///
575 /// The `address` parameter identifies the component by its UUID. The `method` parameter
576 /// identifies the method by its name. The `params` parameter, if present, contains a
577 /// CBOR-encoded array of parameters to pass to the method.
578 ///
579 /// # Errors
580 /// * [`CborDecode`](Error::CborDecode) is returned if the `params` parameter is present but
581 /// contains an invalid or unsupported CBOR sequence.
582 /// * [`BadDescriptor`](Error::BadDescriptor) is returned if the parameters contain a
583 /// descriptor reference to a descriptor that is not open.
584 /// * [`TooManyDescriptors`](Error::TooManyDescriptors) is returned if the descriptor table is
585 /// too full and some descriptors must be closed before another method call can be made.
586 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
587 pub fn component_method<'invoker>(
588 &'invoker mut self,
589 address: &Address,
590 method: &str,
591 params: Option<&[u8]>,
592 ) -> Result<(InvokeResult, MethodCall<'invoker>)> {
593 let address = address.as_bytes();
594 let params_ptr = params.map_or(ptr::null(), <[u8]>::as_ptr);
595 let done = Error::from_i32(
596 // SAFETY: invoke_component_method permits an input UUID pointer, method name
597 // pointer/length pair, and CBOR pointer which may be null.
598 unsafe {
599 sys::invoke_component_method(
600 address.as_ptr(),
601 method.as_ptr(),
602 method.len(),
603 params_ptr,
604 )
605 },
606 )? != 0;
607 Ok((
608 if done {
609 InvokeResult::Complete
610 } else {
611 InvokeResult::Incomplete
612 },
613 MethodCall(PhantomData),
614 ))
615 }
616
617 /// Starts invoking a callable opaque value.
618 ///
619 /// The `descriptor` parameter identifies the opaque value by its descriptor. The `params`
620 /// parameter, if present, contains a CBOR-encoded array of parameters to pass to the method.
621 ///
622 /// # Errors
623 /// * [`CborDecode`](Error::CborDecode) is returned if the `params` parameter is present but
624 /// contains an invalid or unsupported CBOR sequence.
625 /// * [`BadDescriptor`](Error::BadDescriptor) is returned if the parameters contain a
626 /// descriptor reference to a descriptor that is not open.
627 /// * [`TooManyDescriptors`](Error::TooManyDescriptors) is returned if the descriptor table is
628 /// too full and some descriptors must be closed before another method call can be made.
629 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
630 pub fn value<'invoker>(
631 &'invoker mut self,
632 descriptor: &impl AsDescriptor,
633 params: Option<&[u8]>,
634 ) -> Result<(InvokeResult, MethodCall<'invoker>)> {
635 let params_ptr = params.map_or(ptr::null(), <[u8]>::as_ptr);
636 let done = Error::from_i32(
637 // SAFETY: invoke_value permits any descriptor and a CBOR pointer which may be null.
638 unsafe { sys::invoke_value(descriptor.as_descriptor().as_raw(), params_ptr) },
639 )? != 0;
640 Ok((
641 if done {
642 InvokeResult::Complete
643 } else {
644 InvokeResult::Incomplete
645 },
646 MethodCall(PhantomData),
647 ))
648 }
649
650 /// Starts reading from an index of an opaque value.
651 ///
652 /// The `descriptor` parameter identifies the opaque value by its descriptor. The `params`
653 /// parameter, if present, contains a CBOR-encoded array of parameters to use for indexing.
654 ///
655 /// # Errors
656 /// * [`CborDecode`](Error::CborDecode) is returned if the `params` parameter is present but
657 /// contains an invalid or unsupported CBOR sequence.
658 /// * [`BadDescriptor`](Error::BadDescriptor) is returned if the parameters contain a
659 /// descriptor reference to a descriptor that is not open.
660 /// * [`TooManyDescriptors`](Error::TooManyDescriptors) is returned if the descriptor table is
661 /// too full and some descriptors must be closed before another method call can be made.
662 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
663 pub fn value_indexed_read<'invoker>(
664 &'invoker mut self,
665 descriptor: &impl AsDescriptor,
666 params: Option<&[u8]>,
667 ) -> Result<(InvokeResult, MethodCall<'invoker>)> {
668 let params_ptr = params.map_or(ptr::null(), <[u8]>::as_ptr);
669 let done = Error::from_i32(
670 // SAFETY: invoke_value_indexed_read permits any descriptor and a CBOR pointer which
671 // may be null.
672 unsafe {
673 sys::invoke_value_indexed_read(descriptor.as_descriptor().as_raw(), params_ptr)
674 },
675 )? != 0;
676 Ok((
677 if done {
678 InvokeResult::Complete
679 } else {
680 InvokeResult::Incomplete
681 },
682 MethodCall(PhantomData),
683 ))
684 }
685
686 /// Starts writing to an index of an opaque value.
687 ///
688 /// The `descriptor` parameter identifies the opaque value by its descriptor. The `params`
689 /// parameter, if present, contains a CBOR-encoded array of parameters to use for indexing and
690 /// the value to write.
691 ///
692 /// # Errors
693 /// * [`CborDecode`](Error::CborDecode) is returned if the `params` parameter is present but
694 /// contains an invalid or unsupported CBOR sequence.
695 /// * [`BadDescriptor`](Error::BadDescriptor) is returned if the parameters contain a
696 /// descriptor reference to a descriptor that is not open.
697 /// * [`TooManyDescriptors`](Error::TooManyDescriptors) is returned if the descriptor table is
698 /// too full and some descriptors must be closed before another method call can be made.
699 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
700 pub fn value_indexed_write<'invoker>(
701 &'invoker mut self,
702 descriptor: &impl AsDescriptor,
703 params: Option<&[u8]>,
704 ) -> Result<(InvokeResult, MethodCall<'invoker>)> {
705 let params_ptr = params.map_or(ptr::null(), <[u8]>::as_ptr);
706 let done = Error::from_i32(
707 // SAFETY: invoke_value_indexed_write permits any descriptor and a CBOR pointer which
708 // may be null.
709 unsafe {
710 sys::invoke_value_indexed_write(descriptor.as_descriptor().as_raw(), params_ptr)
711 },
712 )? != 0;
713 Ok((
714 if done {
715 InvokeResult::Complete
716 } else {
717 InvokeResult::Incomplete
718 },
719 MethodCall(PhantomData),
720 ))
721 }
722
723 /// Starts invoking a method on an opaque value.
724 ///
725 /// The `descriptor` parameter identifies the opaque value by its descriptor. The `method`
726 /// parameter identifies the method by its name. The `params` parameter, if present, contains a
727 /// CBOR-encoded array of parameters to pass to the method.
728 ///
729 /// # Errors
730 /// * [`CborDecode`](Error::CborDecode) is returned if the `params` parameter is present but
731 /// contains an invalid or unsupported CBOR sequence.
732 /// * [`BadDescriptor`](Error::BadDescriptor) is returned if the parameters contain a
733 /// descriptor reference to a descriptor that is not open.
734 /// * [`TooManyDescriptors`](Error::TooManyDescriptors) is returned if the descriptor table is
735 /// too full and some descriptors must be closed before another method call can be made.
736 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
737 pub fn value_method<'invoker>(
738 &'invoker mut self,
739 descriptor: &impl AsDescriptor,
740 method: &str,
741 params: Option<&[u8]>,
742 ) -> Result<(InvokeResult, MethodCall<'invoker>)> {
743 let params_ptr = params.map_or(ptr::null(), <[u8]>::as_ptr);
744 let done = Error::from_i32(
745 // SAFETY: invoke_value_method permits any descriptor, a string pointer/length pair, and a
746 // CBOR pointer which may be null.
747 unsafe {
748 sys::invoke_value_method(
749 descriptor.as_descriptor().as_raw(),
750 method.as_ptr(),
751 method.len(),
752 params_ptr,
753 )
754 },
755 )? != 0;
756 Ok((
757 if done {
758 InvokeResult::Complete
759 } else {
760 InvokeResult::Incomplete
761 },
762 MethodCall(PhantomData),
763 ))
764 }
765}
766
767impl core::fmt::Debug for Invoker {
768 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
769 write!(f, "Invoker")
770 }
771}
772
773impl PartialEq for Invoker {
774 fn eq(&self, _: &Self) -> bool {
775 // Only one invoker can ever exist, therefore all invokers that exist are equal.
776 true
777 }
778}
779
780impl Eq for Invoker {}
781
782/// The possible results of a successful start to a method call.
783#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
784pub enum InvokeResult {
785 /// The method is complete and its result can be fetched immediately.
786 Complete,
787
788 /// The method is not finished yet; its result can be fetched on the next timeslice.
789 Incomplete,
790}
791
792/// An in-progress method call.
793///
794/// The `'invoker` lifetime parameter is the lifetime of the method invoker that is performing the
795/// call.
796///
797/// If a value of this type is dropped, the method call is cancelled. If it has not executed yet,
798/// it will not execute; if it has already executed, its result is discarded.
799#[derive(Debug, Eq, PartialEq)]
800#[must_use = "Discarding a MethodCall immediately is buggy. Even if you know the method you are calling is direct and don’t need its return value, direct methods must be run indirectly if the method call cost limit is reached, so you still need to make sure it finishes."]
801pub struct MethodCall<'invoker>(PhantomData<&'invoker mut Invoker>);
802
803impl<'invoker> MethodCall<'invoker> {
804 /// Returns the length, in bytes, of the result of the method call, or an indication that the
805 /// call is not finished.
806 ///
807 /// On success, the length and the `MethodCall` are returned, allowing the `MethodCall` to be
808 /// reused to fetch the actual bytes.
809 ///
810 /// # Errors
811 /// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the method call failed because
812 /// the component does not exist or is inaccessible.
813 /// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method call failed because the
814 /// method does not exist on the component.
815 /// * [`BadParameters`](Error::BadParameters) is returned if the parameters provided when
816 /// starting the call are not acceptable for the method.
817 /// * [`Other`](Error::Other) is returned if the method call failed.
818 #[must_use = "This function is only useful for its return value"]
819 pub fn end_length(self) -> InvokeEndLengthResult<'invoker> {
820 // SAFETY: invoke_end permits null.
821 let ret = unsafe { sys::invoke_end(ptr::null_mut(), 0) };
822 match MethodCallError::from_isize(PhantomData, ret) {
823 Ok(n) => InvokeEndLengthResult::Done(Ok((n, self))),
824 Err(MethodCallError::QueueEmpty) => InvokeEndLengthResult::Pending(self),
825 Err(e) => InvokeEndLengthResult::Done(Err(e)),
826 }
827 }
828
829 /// Returns the result of the method call as a CBOR-encoded data item, or an indication that
830 /// the call is not finished.
831 ///
832 /// On success, the result is written into up to `len` bytes pointed to by `buffer`, and the
833 /// number of bytes written is returned. If the buffer is not large enough to hold the call
834 /// result, [`BufferTooShort`](InvokeEndResult::BufferTooShort) is returned, containing the
835 /// `MethodCall` object, allowing the caller to retry fetching the results with a larger
836 /// buffer, or call [`end_length`](MethodCall::end_length) to obtain the needed buffer size.
837 ///
838 /// # Errors
839 /// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the method call failed because the
840 /// component does not exist or is inaccessible.
841 /// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method call failed because the
842 /// method does not exist on the component.
843 /// * [`BadParameters`](Error::BadParameters) is returned if the parameters provided when
844 /// starting the call are not acceptable for the method.
845 /// * [`Other`](Error::Other) is returned if the method call failed.
846 ///
847 /// # Safety
848 /// The caller must ensure that `len` bytes pointed to by `buffer` are writeable.
849 pub unsafe fn end_ptr(self, buffer: *mut u8, len: usize) -> InvokeEndResult<'invoker> {
850 let result = sys::invoke_end(buffer, len);
851 match MethodCallError::from_isize(PhantomData, result) {
852 Err(MethodCallError::BufferTooShort) => InvokeEndResult::BufferTooShort(self),
853 Err(MethodCallError::QueueEmpty) => InvokeEndResult::Pending(self),
854 other => InvokeEndResult::Done(other),
855 }
856 }
857
858 /// Returns the result of the method call as a CBOR-encoded data item, or an indication that
859 /// the call is not finished.
860 ///
861 /// On success, the result is written into `buffer`, and the number of bytes written is
862 /// returned. If the buffer is not large enough to hold the call result,
863 /// [`BufferTooShort`](InvokeEndResult::BufferTooShort) is returned, containing the
864 /// `MethodCall` object, allowing the caller to retry fetching the results with a larger
865 /// buffer, or call [`end_length`](MethodCall::end_length) to obtain the needed buffer size.
866 ///
867 /// # Errors
868 /// * [`NoSuchComponent`](Error::NoSuchComponent) is returned if the method call failed because the
869 /// component does not exist or is inaccessible.
870 /// * [`NoSuchMethod`](Error::NoSuchMethod) is returned if the method call failed because the
871 /// method does not exist on the component.
872 /// * [`BadParameters`](Error::BadParameters) is returned if the parameters provided when
873 /// starting the call are not acceptable for the method.
874 /// * [`Other`](Error::Other) is returned if the method call failed.
875 pub fn end(self, buffer: &mut [u8]) -> InvokeEndResult<'invoker> {
876 // SAFETY: invoke_end permits a writeable buffer pointer/length pair and promises to always
877 // return the length of data it wrote.
878 let result = unsafe { sys::invoke_end(buffer.as_mut_ptr(), buffer.len()) };
879 match MethodCallError::from_isize(PhantomData, result) {
880 Err(MethodCallError::BufferTooShort) => InvokeEndResult::BufferTooShort(self),
881 Err(MethodCallError::QueueEmpty) => InvokeEndResult::Pending(self),
882 other => InvokeEndResult::Done(other),
883 }
884 }
885}
886
887impl Drop for MethodCall<'_> {
888 fn drop(&mut self) {
889 // SAFETY: invoke_cancel is unconditionally safe.
890 unsafe { sys::invoke_cancel() }
891 }
892}
893
894/// An object that is able to retrieve detailed method call error information.
895///
896/// Certain errors, when returned from a method call (and only from a method call!), are
897/// accompanied by additional detailed error information which is only available until the next
898/// method call. A value of this type uses the `'invoker` lifetime parameter to prevent additional
899/// method calls from being made until the caller has finished examining the detailed error
900/// information.
901#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
902pub struct LastException<'invoker>(PhantomData<&'invoker mut Invoker>);
903
904impl<'invoker> LastException<'invoker> {
905 /// Creates a new `LastException`.
906 fn new(_: PhantomData<&'invoker mut Invoker>) -> Self {
907 Self(PhantomData)
908 }
909
910 /// Returns the length of the human-readable message for the error.
911 ///
912 /// # Panics
913 /// This function panics if the underlying syscall fails, because the only reasons it could
914 /// fail should be impossible due to the type system.
915 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
916 #[must_use = "This function is only useful for its return value"]
917 pub fn message_length(&self) -> usize {
918 // SAFETY: last_exception_message permits null.
919 let result = unsafe { call_buffer_len(sys::last_exception_message) };
920 result.unwrap_or_else(|_| panic_or_trap!("unreachable"))
921 }
922
923 /// Returns the human-readable message for the error.
924 ///
925 /// The message is written into `buffer`, and a string slice over the written text is returned.
926 ///
927 /// # Errors
928 /// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is not long enough to
929 /// hold the error message.
930 ///
931 /// # Panics
932 /// This function panics if the underlying syscall fails for any reason other than
933 /// [`BufferTooShort`](Error::BufferTooShort), because the only other reasons it could fail
934 /// should be impossible due to the type system.
935 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
936 pub fn message<'buf>(&self, buffer: &'buf mut [u8]) -> Result<&'buf str> {
937 // SAFETY: last_exception permits a writeable buffer output pointer/length pair and
938 // promises to always write a valid UTF-8 string and return its length.
939 let result = unsafe { call_buffer_str(sys::last_exception_message, buffer) };
940 match result {
941 Ok(message) => Ok(message),
942 Err(Error::BufferTooShort) => Err(Error::BufferTooShort),
943 Err(_) => panic_or_trap!("unreachable"),
944 }
945 }
946
947 /// Checks whether the Java exception underlying the error is of a certain type.
948 ///
949 /// The `class` parameter must be the fully qualified name of a Java class (e.g.
950 /// `java.io.IOException`). This function returns `true` if the exception that caused the error
951 /// is `class` or a subclass thereof, or `false` if not.
952 ///
953 /// # Panics
954 /// This function panics if the underlying syscall fails, because the only reasons it could
955 /// fail should be impossible due to the type system.
956 #[allow(clippy::unused_self)] // Not used for its value, but used for its lifetime.
957 #[must_use = "This function is only useful for its return value"]
958 pub fn is_type(&self, class: &str) -> bool {
959 // SAFETY: is_type permits a string pointer/length pair.
960 let result = unsafe { call_string(sys::last_exception_is_type, Some(class)) };
961 result.unwrap_or_else(|_| panic_or_trap!("unreachable")) != 0
962 }
963}
964
965/// The possible errors that could occur during a method call.
966///
967/// Some errors carry additional information. This information is only available until the start of
968/// the next method call. The `'invoker` lifetime ensures that the invoker cannot be reused to
969/// start another method call until a value of this type is dropped and therefore the additional
970/// error information is no longer accessible.
971#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
972pub enum MethodCallError<'invoker> {
973 CborDecode,
974 BufferTooShort,
975 NoSuchComponent,
976 NoSuchMethod,
977 BadParameters(LastException<'invoker>),
978 QueueFull,
979 QueueEmpty,
980 BadDescriptor,
981 TooManyDescriptors,
982 Other(LastException<'invoker>),
983 Unknown,
984}
985
986impl<'invoker> MethodCallError<'invoker> {
987 /// Checks a system call return value of type `isize` for an error value.
988 ///
989 /// Returns a `Result` containing a `MethodCallError` if the value is negative, or the
990 /// original value if it was nonnegative.
991 ///
992 /// # Errors
993 /// This function fails if the parameter is negative, decoding the represented error code.
994 ///
995 /// # Panics
996 /// This function panics if the syscall error code is `MemoryFault` or `StringDecode`. These
997 /// syscall errors should be impossible in safe code because the type system prohibits them:
998 /// `MemoryFault` should be impossible because all memory regions are taken as slices which are
999 /// always valid, and `StringDecode` should be impossible because all strings are taken as
1000 /// string-slices (`&str`) which are always valid UTF-8.
1001 fn from_isize(
1002 _: PhantomData<&'invoker mut Invoker>,
1003 value: isize,
1004 ) -> core::result::Result<usize, MethodCallError<'invoker>> {
1005 match value {
1006 -1 => panic_or_trap!("Memory fault"), // Impossible due to memory safety
1007 -2 => Err(Self::CborDecode),
1008 -3 => panic_or_trap!("String decode error"), // Impossible due to type safety of &str
1009 -4 => Err(Self::BufferTooShort),
1010 -5 => Err(Self::NoSuchComponent),
1011 -6 => Err(Self::NoSuchMethod),
1012 -7 => Err(Self::BadParameters(LastException::new(PhantomData))),
1013 -8 => Err(Self::QueueFull),
1014 -9 => Err(Self::QueueEmpty),
1015 -10 => Err(Self::BadDescriptor),
1016 -11 => Err(Self::TooManyDescriptors),
1017 -12 => Err(Self::Other(LastException::new(PhantomData))),
1018 x if x < 0 => Err(Self::Unknown),
1019 _ => {
1020 // Cast from isize to usize is safe because the match arm verifies that x ≥ 0.
1021 #[allow(clippy::cast_sign_loss)]
1022 Ok(value as usize)
1023 }
1024 }
1025 }
1026
1027 /// Returns a string describing the error.
1028 #[must_use = "This function is only useful for its return value"]
1029 pub fn as_str(self) -> &'static str {
1030 self.simplify().as_str()
1031 }
1032
1033 /// Throws away the additional error information.
1034 #[must_use = "This function is only useful for its return value"]
1035 pub fn simplify(self) -> Error {
1036 match self {
1037 Self::CborDecode => Error::CborDecode,
1038 Self::BufferTooShort => Error::BufferTooShort,
1039 Self::NoSuchComponent => Error::NoSuchComponent,
1040 Self::NoSuchMethod => Error::NoSuchMethod,
1041 Self::BadParameters(_) => Error::BadParameters,
1042 Self::QueueFull => Error::QueueFull,
1043 Self::QueueEmpty => Error::QueueEmpty,
1044 Self::BadDescriptor => Error::BadDescriptor,
1045 Self::TooManyDescriptors => Error::TooManyDescriptors,
1046 Self::Other(_) => Error::Other,
1047 Self::Unknown => Error::Unknown,
1048 }
1049 }
1050}
1051
1052impl Display for MethodCallError<'_> {
1053 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1054 self.simplify().fmt(f)
1055 }
1056}
1057
1058impl From<MethodCallError<'_>> for Error {
1059 fn from(source: MethodCallError<'_>) -> Self {
1060 source.simplify()
1061 }
1062}
1063
1064impl TryFrom<Error> for MethodCallError<'static> {
1065 type Error = ();
1066
1067 fn try_from(source: Error) -> core::result::Result<Self, Self::Error> {
1068 match source {
1069 Error::CborDecode => Ok(Self::CborDecode),
1070 Error::BufferTooShort => Ok(Self::BufferTooShort),
1071 Error::NoSuchComponent => Ok(Self::NoSuchComponent),
1072 Error::NoSuchMethod => Ok(Self::NoSuchMethod),
1073 Error::QueueFull => Ok(Self::QueueFull),
1074 Error::QueueEmpty => Ok(Self::QueueEmpty),
1075 Error::BadDescriptor => Ok(Self::BadDescriptor),
1076 Error::TooManyDescriptors => Ok(Self::TooManyDescriptors),
1077 Error::Unknown => Ok(Self::Unknown),
1078 Error::BadParameters | Error::Other => Err(()),
1079 }
1080 }
1081}
1082
1083#[cfg(feature = "std")]
1084impl std::error::Error for MethodCallError<'_> {}
1085
1086/// The result of a call to [`end_length`](MethodCall::end_length).
1087///
1088/// The `'invoker` lifetime parameter is the lifetime of the method invoker that is performing the
1089/// call.
1090#[derive(Debug, Eq, PartialEq)]
1091pub enum InvokeEndLengthResult<'invoker> {
1092 /// The method call is complete. If the method call completed successfully, the `Result` value
1093 /// contains both the length of the call result, in bytes, and the [`MethodCall`] value that
1094 /// can be used to fetch the result if desired. If the method call failed, the `Result` value
1095 /// contains the error.
1096 Done(core::result::Result<(usize, MethodCall<'invoker>), MethodCallError<'invoker>>),
1097
1098 /// The method call is not finished yet. The [`MethodCall`] value is returned so the caller can
1099 /// continue to monitor progress.
1100 Pending(MethodCall<'invoker>),
1101}
1102
1103/// The result of a call to [`end`](MethodCall::end).
1104///
1105/// The `'invoker` lifetime parameter is the lifetime of the method invoker that is performing the
1106/// call.
1107#[derive(Debug, Eq, PartialEq)]
1108pub enum InvokeEndResult<'invoker> {
1109 /// The method call is complete and the result has been fetched. If the method call completed
1110 /// successfully, the `Result` value contains the CBOR-encoded result. If the method call
1111 /// failed, the `Result` value contains an error.
1112 Done(core::result::Result<usize, MethodCallError<'invoker>>),
1113
1114 /// The method call is complete but the provided buffer was too short to hold the result. The
1115 /// [`MethodCall`] value is returned so the caller can retry with a larger buffer.
1116 BufferTooShort(MethodCall<'invoker>),
1117
1118 /// The method call is not finished yet. The [`MethodCall`] value is returned so the caller can
1119 /// continue to monitor progress.
1120 Pending(MethodCall<'invoker>),
1121}
1122
1123impl<'invoker> InvokeEndResult<'invoker> {
1124 /// Unwraps an `InvokeEndResult`, assuming that the caller already knows that the result is
1125 /// `Done`. This function is useful if the caller knows that the method call is complete and
1126 /// that the buffer is large enough to hold any possible return value, or if the caller is not
1127 /// in a position to handle large return values anyway.
1128 ///
1129 /// # Errors
1130 /// * [`BufferTooShort`](MethodCallError::BufferTooShort) is returned if the result was
1131 /// actually `BufferTooShort`.
1132 /// * [`QueueEmpty`](MethodCallError::QueueEmpty) is returned if the result was actually
1133 /// `QueueEmpty`.
1134 ///
1135 /// In case of any error, because the [`MethodCall`] is consumed, the method call is cancelled.
1136 #[must_use = "This function is only useful for its return value"]
1137 pub fn expect_done(self) -> core::result::Result<usize, MethodCallError<'invoker>> {
1138 match self {
1139 Self::Done(result) => result,
1140 Self::BufferTooShort(_) => Err(MethodCallError::BufferTooShort),
1141 Self::Pending(_) => Err(MethodCallError::QueueEmpty),
1142 }
1143 }
1144}