Skip to content

Commit

Permalink
Merge pull request #1073 from neon-bindings/kv/extract-box
Browse files Browse the repository at this point in the history
feat(neon): Add neon::types::extract::Boxed for JsBox conversions
  • Loading branch information
kjvalencik authored Oct 7, 2024
2 parents 482293e + 3367d20 commit 205ed38
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
79 changes: 79 additions & 0 deletions crates/neon/src/types_impl/extract/boxed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use crate::{
context::{Context, Cx},
handle::Handle,
result::{JsResult, NeonResult, ResultExt},
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())),
}
}

fn from_js(cx: &mut Cx<'cx>, v: Handle<'cx, JsValue>) -> NeonResult<Self> {
Self::try_from_js(cx, v)?.or_throw(cx)
}
}

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> {}
3 changes: 2 additions & 1 deletion crates/neon/src/types_impl/extract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,13 @@ use crate::{
types::{JsValue, Value},
};

pub use self::{error::Error, with::With};
pub use self::{boxed::Boxed, error::Error, with::With};

#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub use self::json::Json;

mod boxed;
mod error;
#[cfg(feature = "serde")]
mod json;
Expand Down

0 comments on commit 205ed38

Please sign in to comment.