neon/types_impl/extract/
boxed.rs

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
use crate::{
    context::{Context, Cx},
    handle::Handle,
    result::{JsResult, NeonResult},
    types::{
        extract::{private, TryFromJs, TryIntoJs, TypeExpected},
        Finalize, JsBox, JsValue,
    },
};

/// Wrapper to extract `T` from a [`JsBox<T>`](JsBox) or create a [`JsBox`]
/// from a `T`.
///
/// [`Boxed`] is especially useful for exporting async functions and tasks.
///
/// ```
/// # use std::sync::Arc;
/// # use neon::{prelude::*, types::extract::Boxed};
/// struct Greeter {
///     greeting: String,
/// }
///
/// impl Finalize for Greeter {}
///
/// impl Greeter {
///     fn new(greeting: String) -> Self {
///         Self { greeting }
///     }
///
///     fn greet(&self, name: &str) -> String {
///         format!("{}, {name}!", self.greeting)
///     }
/// }
///
/// #[neon::export]
/// fn create_greeter(greeting: String) -> Boxed<Arc<Greeter>> {
///     Boxed(Arc::new(Greeter::new(greeting)))
/// }
///
/// #[neon::export(task)]
/// fn greet(Boxed(greeter): Boxed<Arc<Greeter>>, name: String) -> String {
///     greeter.greet(&name)
/// }
/// ```
pub struct Boxed<T>(pub T);

impl<'cx, T> TryFromJs<'cx> for Boxed<T>
where
    T: Clone + 'static,
{
    type Error = TypeExpected<JsBox<T>>;

    fn try_from_js(
        cx: &mut Cx<'cx>,
        v: Handle<'cx, JsValue>,
    ) -> NeonResult<Result<Self, Self::Error>> {
        match v.downcast::<JsBox<T>, _>(cx) {
            Ok(v) => Ok(Ok(Self(T::clone(&v)))),
            Err(_) => Ok(Err(TypeExpected::new())),
        }
    }
}

impl<'cx, T> TryIntoJs<'cx> for Boxed<T>
where
    T: Finalize + 'static,
{
    type Value = JsBox<T>;

    fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
        Ok(cx.boxed(self.0))
    }
}

impl<T> private::Sealed for Boxed<T> {}