|
| 1 | +use std::marker::PhantomData; |
| 2 | + |
1 | 3 | use crate::{ |
2 | 4 | context::Cx, |
3 | 5 | handle::Handle, |
4 | 6 | result::{JsResult, NeonResult}, |
5 | 7 | types::{ |
6 | | - buffer::{Binary, TypedArray}, |
| 8 | + buffer::{Binary, TypedArray as _}, |
7 | 9 | 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, |
11 | 11 | }, |
12 | 12 | }; |
13 | 13 |
|
@@ -177,64 +177,109 @@ where |
177 | 177 | { |
178 | 178 | } |
179 | 179 |
|
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>>; |
0 commit comments