Skip to content

Commit bc6c385

Browse files
committed
feat(neon): Implement typed array extractors with a trait
1 parent efa0877 commit bc6c385

2 files changed

Lines changed: 112 additions & 66 deletions

File tree

crates/neon/src/types_impl/extract/buffer.rs

Lines changed: 110 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
use std::marker::PhantomData;
2+
13
use crate::{
24
context::Cx,
35
handle::Handle,
46
result::{JsResult, NeonResult},
57
types::{
6-
buffer::{Binary, TypedArray},
8+
buffer::{Binary, TypedArray as _},
79
extract::{private, TryFromJs, TryIntoJs, TypeExpected},
8-
JsArrayBuffer, JsBigInt64Array, JsBigUint64Array, JsBuffer, JsFloat32Array, JsFloat64Array,
9-
JsInt16Array, JsInt32Array, JsInt8Array, JsTypedArray, JsUint16Array, JsUint32Array,
10-
JsUint8Array, JsValue, Value,
10+
JsArrayBuffer, JsBuffer, JsTypedArray, JsValue, Value,
1111
},
1212
};
1313

@@ -177,64 +177,109 @@ where
177177
{
178178
}
179179

180-
macro_rules! typed_array {
181-
($js:ident, $name:ident, $type:ty) => {
182-
#[doc = concat!(
183-
"Wrapper for converting between a Rust `[",
184-
stringify!($type),
185-
"]` array type and a [`",
186-
stringify!($js),
187-
"`]",
188-
)]
189-
pub struct $name<T>(pub T);
190-
191-
impl<'cx, T> TryIntoJs<'cx> for $name<T>
192-
where
193-
T: AsRef<[$type]>,
194-
{
195-
type Value = $js;
196-
197-
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
198-
$js::from_slice(cx, self.0.as_ref())
199-
}
200-
}
201-
202-
impl<'cx, T> TryFromJs<'cx> for $name<T>
203-
where
204-
for<'a> T: From<&'a [$type]>,
205-
{
206-
type Error = TypeExpected<$js>;
207-
208-
fn try_from_js(
209-
cx: &mut Cx<'cx>,
210-
v: Handle<'cx, JsValue>,
211-
) -> NeonResult<Result<Self, Self::Error>> {
212-
let v = match v.downcast::<$js, _>(cx) {
213-
Ok(v) => v,
214-
Err(_) => return Ok(Err(TypeExpected::new())),
215-
};
216-
217-
Ok(Ok(Self(T::from(v.as_slice(cx)))))
218-
}
219-
}
220-
221-
impl<T> private::Sealed for $name<T> {}
222-
};
223-
224-
($(($js:ident, $name:ident, $type:ty),)*) => {
225-
$(typed_array!($js, $name, $type);)*
226-
};
227-
}
228-
229-
typed_array![
230-
(JsInt8Array, Int8Array, i8),
231-
(JsUint8Array, Uint8Array, u8),
232-
(JsInt16Array, Int16Array, i16),
233-
(JsUint16Array, Uint16Array, u16),
234-
(JsInt32Array, Int32Array, i32),
235-
(JsUint32Array, Uint32Array, u32),
236-
(JsFloat32Array, Float32Array, f32),
237-
(JsFloat64Array, Float64Array, f64),
238-
(JsBigInt64Array, BigInt64Array, i64),
239-
(JsBigUint64Array, BigUint64Array, u64),
240-
];
180+
/// Describes the type of [`JsTypedArray`] associated with a container
181+
///
182+
/// Only implemented for [`TypedArrayMarker`].
183+
pub trait TypedArrayExtract: private::Sealed {
184+
type Container;
185+
type Item: Binary;
186+
}
187+
188+
/// Marker type used to describe the type of [`JsTypedArray`] and associated container
189+
///
190+
/// See [`TypedArray`] for usage.
191+
// N.B.: This is used as an alternative to `PhantomData` to allow single field
192+
// destructuring and constructing without a call to `new`.
193+
pub struct TypedArrayMarker<C, I>(PhantomData<C>, PhantomData<I>);
194+
195+
impl<C, I> TypedArrayExtract for TypedArrayMarker<C, I>
196+
where
197+
I: Binary,
198+
{
199+
type Container = C;
200+
type Item = I;
201+
}
202+
203+
impl<C, I> private::Sealed for TypedArrayMarker<C, I> {}
204+
205+
/// ```
206+
/// # mod bytes { pub type Bytes = Vec<u8>; }
207+
/// use bytes::Bytes;
208+
/// use neon::types::extract::{TypedArray, Uint8Array};
209+
///
210+
/// #[neon::export]
211+
/// fn example(TypedArray(buf): Uint8Array<Bytes>) -> Uint8Array<Bytes> {
212+
/// let buf = Bytes::from(b"Hello, World!");
213+
///
214+
/// TypedArray(buf)
215+
/// }
216+
/// ```
217+
pub struct TypedArray<T>(pub T::Container)
218+
where
219+
T: TypedArrayExtract;
220+
221+
impl<'cx, T> TryIntoJs<'cx> for TypedArray<T>
222+
where
223+
T: TypedArrayExtract,
224+
T::Container: AsRef<[T::Item]>,
225+
JsTypedArray<T::Item>: Value,
226+
{
227+
type Value = JsTypedArray<T::Item>;
228+
229+
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
230+
JsTypedArray::from_slice(cx, self.0.as_ref())
231+
}
232+
}
233+
234+
impl<'cx, T> TryFromJs<'cx> for TypedArray<T>
235+
where
236+
T: TypedArrayExtract,
237+
for<'a> T::Container: From<&'a [T::Item]>,
238+
JsTypedArray<T::Item>: Value,
239+
{
240+
type Error = TypeExpected<JsTypedArray<T::Item>>;
241+
242+
fn try_from_js(
243+
cx: &mut Cx<'cx>,
244+
v: Handle<'cx, JsValue>,
245+
) -> NeonResult<Result<Self, Self::Error>> {
246+
let v = match v.downcast::<JsTypedArray<T::Item>, _>(cx) {
247+
Ok(v) => v,
248+
Err(_) => return Ok(Err(Self::Error::new())),
249+
};
250+
251+
Ok(Ok(Self(T::Container::from(v.as_slice(cx)))))
252+
}
253+
}
254+
255+
impl<T> private::Sealed for TypedArray<T> where T: TypedArrayExtract {}
256+
257+
/// Extractor for [`JsInt8Array`](crate::types::JsInt8Array)
258+
pub type Int8Array<T> = TypedArray<TypedArrayMarker<T, i8>>;
259+
260+
/// Extractor for [`JsUint8Array`](crate::types::JsUint8Array)
261+
pub type Uint8Array<T> = TypedArray<TypedArrayMarker<T, u8>>;
262+
263+
/// Extractor for [`JsInt16Array`](crate::types::JsInt16Array)
264+
pub type Int16Array<T> = TypedArray<TypedArrayMarker<T, i16>>;
265+
266+
/// Extractor for [`JsUint16Array`](crate::types::JsUint16Array)
267+
pub type Uint16Array<T> = TypedArray<TypedArrayMarker<T, u16>>;
268+
269+
/// Extractor for [`JsInt32Array`](crate::types::JsInt32Array)
270+
pub type Int32Array<T> = TypedArray<TypedArrayMarker<T, i32>>;
271+
272+
/// Extractor for [`JsUint32Array`](crate::types::JsUint32Array)
273+
pub type Uint32Array<T> = TypedArray<TypedArrayMarker<T, u32>>;
274+
275+
/// Extractor for [`JsFloat32Array`](crate::types::JsFloat32Array)
276+
pub type Float32Array<T> = TypedArray<TypedArrayMarker<T, f32>>;
277+
278+
/// Extractor for [`JsFloat64Array`](crate::types::JsFloat64Array)
279+
pub type Float64Array<T> = TypedArray<TypedArrayMarker<T, f64>>;
280+
281+
/// Extractor for [`JsBigInt64Array`](crate::types::JsBigInt64Array)
282+
pub type BigInt64Array<T> = TypedArray<TypedArrayMarker<T, i64>>;
283+
284+
/// Extractor for [`JsBigUint64Array`](crate::types::JsBigUint64Array)
285+
pub type BigUint64Array<T> = TypedArray<TypedArrayMarker<T, u64>>;

crates/neon/src/types_impl/extract/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ pub use self::{
110110
boxed::Boxed,
111111
buffer::{
112112
ArrayBuffer, BigInt64Array, BigUint64Array, Buffer, Float32Array, Float64Array, Int16Array,
113-
Int32Array, Int8Array, Uint16Array, Uint32Array, Uint8Array,
113+
Int32Array, Int8Array, TypedArray, TypedArrayExtract, TypedArrayMarker, Uint16Array,
114+
Uint32Array, Uint8Array,
114115
},
115116
error::{Error, TypeExpected},
116117
with::With,

0 commit comments

Comments
 (0)