1 //! Representations of JavaScript's core builtin types.
2 //!
3 //! ## Modeling JavaScript Types
4 //!
5 //! All JavaScript values in Neon implement the abstract [`Value`] trait, which
6 //! is the most generic way to work with JavaScript values. Neon provides a
7 //! number of types that implement this trait, each representing a particular
8 //! type of JavaScript value.
9 //!
10 //! By convention, JavaScript types in Neon have the prefix `Js` in their name,
11 //! such as [`JsNumber`](crate::types::JsNumber) (for the JavaScript `number`
12 //! type) or [`JsFunction`](crate::types::JsFunction) (for the JavaScript
13 //! `function` type).
14 //!
15 //! ### Handles and Casts
16 //!
17 //! Access to JavaScript values in Neon works through [handles](crate::handle),
18 //! which ensure the safe interoperation between Rust and the JavaScript garbage
19 //! collector. This means, for example, a Rust variable that stores a JavaScript string
20 //! will have the type `Handle<JsString>` rather than [`JsString`](crate::types::JsString).
21 //!
22 //! Neon types model the JavaScript type hierarchy through the use of *casts*.
23 //! The [`Handle::upcast()`](crate::handle::Handle::upcast) method safely converts
24 //! a handle to a JavaScript value of one type into a handle to a value of its
25 //! supertype. For example, it's safe to treat a [`JsArray`](crate::types::JsArray)
26 //! as a [`JsObject`](crate::types::JsObject), so you can do an "upcast" and it will
27 //! never fail:
28 //!
29 //! ```
30 //! # use neon::prelude::*;
31 //! fn as_object(array: Handle<JsArray>) -> Handle<JsObject> {
32 //!     let object: Handle<JsObject> = array.upcast();
33 //!     object
34 //! }
35 //! ```
36 //!
37 //! Unlike upcasts, the [`Handle::downcast()`](crate::handle::Handle::downcast) method
38 //! requires a runtime check to test a value's type at runtime, so it can fail with
39 //! a [`DowncastError`](crate::handle::DowncastError):
40 //!
41 //! ```
42 //! # use neon::prelude::*;
43 //! fn as_array<'a>(
44 //!     cx: &mut impl Context<'a>,
45 //!     object: Handle<'a, JsObject>
46 //! ) -> JsResult<'a, JsArray> {
47 //!     object.downcast(cx).or_throw(cx)
48 //! }
49 //! ```
50 //!
51 //! ### The JavaScript Type Hierarchy
52 //!
53 //! ![The Neon type hierarchy, described in detail below.][types]
54 //!
55 //! The JavaScript type hierarchy includes:
56 //!
57 //! - [`JsValue`](JsValue): This is the top of the type hierarchy, and can refer to
58 //!   any JavaScript value. (For TypeScript programmers, this can be thought of as
59 //!   similar to TypeScript's [`unknown`][unknown] type.)
60 //! - [`JsObject`](JsObject): This is the top of the object type hierarchy. Object
61 //!   types all implement the [`Object`](crate::object::Object) trait, which allows
62 //!   getting and setting properties.
63 //!   - **Standard object types:** [`JsFunction`](JsFunction), [`JsArray`](JsArray),
64 //!     [`JsDate`](JsDate), and [`JsError`](JsError).
65 //!   - **Typed arrays:** [`JsBuffer`](JsBuffer) and [`JsArrayBuffer`](JsArrayBuffer).
66 //!   - **Custom types:** [`JsBox`](JsBox), a special Neon type that allows the creation
67 //!     of custom objects that own Rust data structures.
68 //! - **Primitive types:** These are the built-in JavaScript datatypes that are not
69 //!   object types: [`JsNumber`](JsNumber), [`JsBoolean`](JsBoolean),
70 //!   [`JsString`](JsString), [`JsNull`](JsNull), and [`JsUndefined`](JsUndefined).
71 //!
72 //! [types]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/types.jpg
73 //! [unknown]: https://mariusschulz.com/blog/the-unknown-type-in-typescript#the-unknown-type
74 
75 pub(crate) mod binary;
76 #[cfg(feature = "napi-1")]
77 pub(crate) mod boxed;
78 #[cfg(feature = "napi-5")]
79 pub(crate) mod date;
80 pub(crate) mod error;
81 
82 pub(crate) mod internal;
83 pub(crate) mod utf8;
84 
85 use self::internal::{FunctionCallback, ValueInternal};
86 use self::utf8::Utf8;
87 use crate::context::internal::Env;
88 use crate::context::{Context, FunctionContext};
89 use crate::handle::internal::SuperType;
90 use crate::handle::{Handle, Managed};
91 use crate::object::{Object, This};
92 use crate::result::{JsResult, JsResultExt, NeonResult, Throw};
93 use crate::types::internal::Callback;
94 use neon_runtime;
95 use neon_runtime::raw;
96 use smallvec::SmallVec;
97 use std::fmt;
98 use std::fmt::Debug;
99 use std::marker::PhantomData;
100 use std::os::raw::c_void;
101 
102 pub use self::binary::{BinaryData, BinaryViewType, JsArrayBuffer, JsBuffer};
103 #[cfg(feature = "napi-1")]
104 pub use self::boxed::{Finalize, JsBox};
105 #[cfg(feature = "napi-5")]
106 pub use self::date::{DateError, DateErrorKind, JsDate};
107 pub use self::error::JsError;
108 
build<'a, T: Managed, F: FnOnce(&mut raw::Local) -> bool>( env: Env, init: F, ) -> JsResult<'a, T>109 pub(crate) fn build<'a, T: Managed, F: FnOnce(&mut raw::Local) -> bool>(
110     env: Env,
111     init: F,
112 ) -> JsResult<'a, T> {
113     unsafe {
114         let mut local: raw::Local = std::mem::zeroed();
115         if init(&mut local) {
116             Ok(Handle::new_internal(T::from_raw(env, local)))
117         } else {
118             Err(Throw)
119         }
120     }
121 }
122 
123 impl<T: Value> SuperType<T> for JsValue {
upcast_internal(v: T) -> JsValue124     fn upcast_internal(v: T) -> JsValue {
125         JsValue(v.to_raw())
126     }
127 }
128 
129 impl<T: Object> SuperType<T> for JsObject {
upcast_internal(v: T) -> JsObject130     fn upcast_internal(v: T) -> JsObject {
131         JsObject(v.to_raw())
132     }
133 }
134 
135 /// The trait shared by all JavaScript values.
136 pub trait Value: ValueInternal {
to_string<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsString>137     fn to_string<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsString> {
138         let env = cx.env();
139         build(env, |out| unsafe {
140             neon_runtime::convert::to_string(out, env.to_raw(), self.to_raw())
141         })
142     }
143 
as_value<'a, C: Context<'a>>(self, _: &mut C) -> Handle<'a, JsValue>144     fn as_value<'a, C: Context<'a>>(self, _: &mut C) -> Handle<'a, JsValue> {
145         JsValue::new_internal(self.to_raw())
146     }
147 }
148 
149 /// A JavaScript value of any type.
150 #[repr(C)]
151 #[derive(Clone, Copy)]
152 pub struct JsValue(raw::Local);
153 
154 impl Value for JsValue {}
155 
156 impl Managed for JsValue {
to_raw(self) -> raw::Local157     fn to_raw(self) -> raw::Local {
158         self.0
159     }
160 
from_raw(_: Env, h: raw::Local) -> Self161     fn from_raw(_: Env, h: raw::Local) -> Self {
162         JsValue(h)
163     }
164 }
165 
166 impl ValueInternal for JsValue {
name() -> String167     fn name() -> String {
168         "any".to_string()
169     }
170 
is_typeof<Other: Value>(_env: Env, _other: Other) -> bool171     fn is_typeof<Other: Value>(_env: Env, _other: Other) -> bool {
172         true
173     }
174 }
175 
176 unsafe impl This for JsValue {
177     #[cfg(feature = "legacy-runtime")]
as_this(h: raw::Local) -> Self178     fn as_this(h: raw::Local) -> Self {
179         JsValue(h)
180     }
181 
182     #[cfg(feature = "napi-1")]
as_this(_env: Env, h: raw::Local) -> Self183     fn as_this(_env: Env, h: raw::Local) -> Self {
184         JsValue(h)
185     }
186 }
187 
188 impl JsValue {
new_internal<'a>(value: raw::Local) -> Handle<'a, JsValue>189     pub(crate) fn new_internal<'a>(value: raw::Local) -> Handle<'a, JsValue> {
190         Handle::new_internal(JsValue(value))
191     }
192 }
193 
194 /// The JavaScript `undefined` value.
195 #[repr(C)]
196 #[derive(Clone, Copy)]
197 pub struct JsUndefined(raw::Local);
198 
199 impl JsUndefined {
200     #[cfg(feature = "legacy-runtime")]
new<'a>() -> Handle<'a, JsUndefined>201     pub fn new<'a>() -> Handle<'a, JsUndefined> {
202         JsUndefined::new_internal(Env::current())
203     }
204 
205     #[cfg(feature = "napi-1")]
new<'a, C: Context<'a>>(cx: &mut C) -> Handle<'a, JsUndefined>206     pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Handle<'a, JsUndefined> {
207         JsUndefined::new_internal(cx.env())
208     }
209 
new_internal<'a>(env: Env) -> Handle<'a, JsUndefined>210     pub(crate) fn new_internal<'a>(env: Env) -> Handle<'a, JsUndefined> {
211         unsafe {
212             let mut local: raw::Local = std::mem::zeroed();
213             neon_runtime::primitive::undefined(&mut local, env.to_raw());
214             Handle::new_internal(JsUndefined(local))
215         }
216     }
217 
218     #[allow(clippy::wrong_self_convention)]
as_this_compat(env: Env, _: raw::Local) -> Self219     fn as_this_compat(env: Env, _: raw::Local) -> Self {
220         unsafe {
221             let mut local: raw::Local = std::mem::zeroed();
222             neon_runtime::primitive::undefined(&mut local, env.to_raw());
223             JsUndefined(local)
224         }
225     }
226 }
227 
228 impl Value for JsUndefined {}
229 
230 impl Managed for JsUndefined {
to_raw(self) -> raw::Local231     fn to_raw(self) -> raw::Local {
232         self.0
233     }
234 
from_raw(_: Env, h: raw::Local) -> Self235     fn from_raw(_: Env, h: raw::Local) -> Self {
236         JsUndefined(h)
237     }
238 }
239 
240 unsafe impl This for JsUndefined {
241     #[cfg(feature = "legacy-runtime")]
as_this(h: raw::Local) -> Self242     fn as_this(h: raw::Local) -> Self {
243         JsUndefined::as_this_compat(Env::current(), h)
244     }
245 
246     #[cfg(feature = "napi-1")]
as_this(env: Env, h: raw::Local) -> Self247     fn as_this(env: Env, h: raw::Local) -> Self {
248         JsUndefined::as_this_compat(env, h)
249     }
250 }
251 
252 impl ValueInternal for JsUndefined {
name() -> String253     fn name() -> String {
254         "undefined".to_string()
255     }
256 
is_typeof<Other: Value>(env: Env, other: Other) -> bool257     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
258         unsafe { neon_runtime::tag::is_undefined(env.to_raw(), other.to_raw()) }
259     }
260 }
261 
262 /// The JavaScript `null` value.
263 #[repr(C)]
264 #[derive(Clone, Copy)]
265 pub struct JsNull(raw::Local);
266 
267 impl JsNull {
268     #[cfg(feature = "legacy-runtime")]
new<'a>() -> Handle<'a, JsNull>269     pub fn new<'a>() -> Handle<'a, JsNull> {
270         JsNull::new_internal(Env::current())
271     }
272 
273     #[cfg(feature = "napi-1")]
new<'a, C: Context<'a>>(cx: &mut C) -> Handle<'a, JsNull>274     pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Handle<'a, JsNull> {
275         JsNull::new_internal(cx.env())
276     }
277 
new_internal<'a>(env: Env) -> Handle<'a, JsNull>278     pub(crate) fn new_internal<'a>(env: Env) -> Handle<'a, JsNull> {
279         unsafe {
280             let mut local: raw::Local = std::mem::zeroed();
281             neon_runtime::primitive::null(&mut local, env.to_raw());
282             Handle::new_internal(JsNull(local))
283         }
284     }
285 }
286 
287 impl Value for JsNull {}
288 
289 impl Managed for JsNull {
to_raw(self) -> raw::Local290     fn to_raw(self) -> raw::Local {
291         self.0
292     }
293 
from_raw(_: Env, h: raw::Local) -> Self294     fn from_raw(_: Env, h: raw::Local) -> Self {
295         JsNull(h)
296     }
297 }
298 
299 impl ValueInternal for JsNull {
name() -> String300     fn name() -> String {
301         "null".to_string()
302     }
303 
is_typeof<Other: Value>(env: Env, other: Other) -> bool304     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
305         unsafe { neon_runtime::tag::is_null(env.to_raw(), other.to_raw()) }
306     }
307 }
308 
309 /// A JavaScript boolean primitive value.
310 #[repr(C)]
311 #[derive(Clone, Copy)]
312 pub struct JsBoolean(raw::Local);
313 
314 impl JsBoolean {
new<'a, C: Context<'a>>(cx: &mut C, b: bool) -> Handle<'a, JsBoolean>315     pub fn new<'a, C: Context<'a>>(cx: &mut C, b: bool) -> Handle<'a, JsBoolean> {
316         JsBoolean::new_internal(cx.env(), b)
317     }
318 
new_internal<'a>(env: Env, b: bool) -> Handle<'a, JsBoolean>319     pub(crate) fn new_internal<'a>(env: Env, b: bool) -> Handle<'a, JsBoolean> {
320         unsafe {
321             let mut local: raw::Local = std::mem::zeroed();
322             neon_runtime::primitive::boolean(&mut local, env.to_raw(), b);
323             Handle::new_internal(JsBoolean(local))
324         }
325     }
326 
327     #[cfg(feature = "legacy-runtime")]
value(self) -> bool328     pub fn value(self) -> bool {
329         unsafe { neon_runtime::primitive::boolean_value(self.to_raw()) }
330     }
331 
332     #[cfg(feature = "napi-1")]
value<'a, C: Context<'a>>(self, cx: &mut C) -> bool333     pub fn value<'a, C: Context<'a>>(self, cx: &mut C) -> bool {
334         let env = cx.env().to_raw();
335         unsafe { neon_runtime::primitive::boolean_value(env, self.to_raw()) }
336     }
337 }
338 
339 impl Value for JsBoolean {}
340 
341 impl Managed for JsBoolean {
to_raw(self) -> raw::Local342     fn to_raw(self) -> raw::Local {
343         self.0
344     }
345 
from_raw(_: Env, h: raw::Local) -> Self346     fn from_raw(_: Env, h: raw::Local) -> Self {
347         JsBoolean(h)
348     }
349 }
350 
351 impl ValueInternal for JsBoolean {
name() -> String352     fn name() -> String {
353         "boolean".to_string()
354     }
355 
is_typeof<Other: Value>(env: Env, other: Other) -> bool356     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
357         unsafe { neon_runtime::tag::is_boolean(env.to_raw(), other.to_raw()) }
358     }
359 }
360 
361 /// A JavaScript string primitive value.
362 #[repr(C)]
363 #[derive(Clone, Copy)]
364 pub struct JsString(raw::Local);
365 
366 /// An error produced when constructing a string that exceeds the JS engine's maximum string size.
367 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
368 pub struct StringOverflow(usize);
369 
370 impl fmt::Display for StringOverflow {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result371     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372         write!(f, "string size out of range: {}", self.0)
373     }
374 }
375 
376 /// The result of constructing a new `JsString`.
377 pub type StringResult<'a> = Result<Handle<'a, JsString>, StringOverflow>;
378 
379 impl<'a> JsResultExt<'a, JsString> for StringResult<'a> {
or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, JsString>380     fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, JsString> {
381         match self {
382             Ok(v) => Ok(v),
383             Err(e) => cx.throw_range_error(&e.to_string()),
384         }
385     }
386 }
387 
388 impl Value for JsString {}
389 
390 impl Managed for JsString {
to_raw(self) -> raw::Local391     fn to_raw(self) -> raw::Local {
392         self.0
393     }
394 
from_raw(_: Env, h: raw::Local) -> Self395     fn from_raw(_: Env, h: raw::Local) -> Self {
396         JsString(h)
397     }
398 }
399 
400 impl ValueInternal for JsString {
name() -> String401     fn name() -> String {
402         "string".to_string()
403     }
404 
is_typeof<Other: Value>(env: Env, other: Other) -> bool405     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
406         unsafe { neon_runtime::tag::is_string(env.to_raw(), other.to_raw()) }
407     }
408 }
409 
410 impl JsString {
411     #[cfg(feature = "legacy-runtime")]
size(self) -> isize412     pub fn size(self) -> isize {
413         unsafe { neon_runtime::string::utf8_len(self.to_raw()) }
414     }
415 
416     #[cfg(feature = "napi-1")]
size<'a, C: Context<'a>>(self, cx: &mut C) -> isize417     pub fn size<'a, C: Context<'a>>(self, cx: &mut C) -> isize {
418         let env = cx.env().to_raw();
419 
420         unsafe { neon_runtime::string::utf8_len(env, self.to_raw()) }
421     }
422 
423     #[cfg(feature = "legacy-runtime")]
value(self) -> String424     pub fn value(self) -> String {
425         unsafe {
426             let capacity = neon_runtime::string::utf8_len(self.to_raw());
427             let mut buffer: Vec<u8> = Vec::with_capacity(capacity as usize);
428             let p = buffer.as_mut_ptr();
429             std::mem::forget(buffer);
430             let len = neon_runtime::string::data(p, capacity, self.to_raw());
431             String::from_raw_parts(p, len as usize, capacity as usize)
432         }
433     }
434 
435     #[cfg(feature = "napi-1")]
value<'a, C: Context<'a>>(self, cx: &mut C) -> String436     pub fn value<'a, C: Context<'a>>(self, cx: &mut C) -> String {
437         let env = cx.env().to_raw();
438 
439         unsafe {
440             let capacity = neon_runtime::string::utf8_len(env, self.to_raw()) + 1;
441             let mut buffer: Vec<u8> = Vec::with_capacity(capacity as usize);
442             let p = buffer.as_mut_ptr();
443             std::mem::forget(buffer);
444             let len = neon_runtime::string::data(env, p, capacity, self.to_raw());
445             String::from_raw_parts(p, len as usize, capacity as usize)
446         }
447     }
448 
new<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, val: S) -> Handle<'a, JsString>449     pub fn new<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, val: S) -> Handle<'a, JsString> {
450         JsString::try_new(cx, val).unwrap()
451     }
452 
try_new<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, val: S) -> StringResult<'a>453     pub fn try_new<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, val: S) -> StringResult<'a> {
454         let val = val.as_ref();
455         match JsString::new_internal(cx.env(), val) {
456             Some(s) => Ok(s),
457             None => Err(StringOverflow(val.len())),
458         }
459     }
460 
new_internal<'a>(env: Env, val: &str) -> Option<Handle<'a, JsString>>461     pub(crate) fn new_internal<'a>(env: Env, val: &str) -> Option<Handle<'a, JsString>> {
462         let (ptr, len) = if let Some(small) = Utf8::from(val).into_small() {
463             small.lower()
464         } else {
465             return None;
466         };
467 
468         unsafe {
469             let mut local: raw::Local = std::mem::zeroed();
470             if neon_runtime::string::new(&mut local, env.to_raw(), ptr, len) {
471                 Some(Handle::new_internal(JsString(local)))
472             } else {
473                 None
474             }
475         }
476     }
477 }
478 
479 /// A JavaScript number value.
480 #[repr(C)]
481 #[derive(Clone, Copy)]
482 pub struct JsNumber(raw::Local);
483 
484 impl JsNumber {
new<'a, C: Context<'a>, T: Into<f64>>(cx: &mut C, x: T) -> Handle<'a, JsNumber>485     pub fn new<'a, C: Context<'a>, T: Into<f64>>(cx: &mut C, x: T) -> Handle<'a, JsNumber> {
486         JsNumber::new_internal(cx.env(), x.into())
487     }
488 
new_internal<'a>(env: Env, v: f64) -> Handle<'a, JsNumber>489     pub(crate) fn new_internal<'a>(env: Env, v: f64) -> Handle<'a, JsNumber> {
490         unsafe {
491             let mut local: raw::Local = std::mem::zeroed();
492             neon_runtime::primitive::number(&mut local, env.to_raw(), v);
493             Handle::new_internal(JsNumber(local))
494         }
495     }
496 
497     #[cfg(feature = "legacy-runtime")]
value(self) -> f64498     pub fn value(self) -> f64 {
499         unsafe { neon_runtime::primitive::number_value(self.to_raw()) }
500     }
501 
502     #[cfg(feature = "napi-1")]
value<'a, C: Context<'a>>(self, cx: &mut C) -> f64503     pub fn value<'a, C: Context<'a>>(self, cx: &mut C) -> f64 {
504         let env = cx.env().to_raw();
505         unsafe { neon_runtime::primitive::number_value(env, self.to_raw()) }
506     }
507 }
508 
509 impl Value for JsNumber {}
510 
511 impl Managed for JsNumber {
to_raw(self) -> raw::Local512     fn to_raw(self) -> raw::Local {
513         self.0
514     }
515 
from_raw(_: Env, h: raw::Local) -> Self516     fn from_raw(_: Env, h: raw::Local) -> Self {
517         JsNumber(h)
518     }
519 }
520 
521 impl ValueInternal for JsNumber {
name() -> String522     fn name() -> String {
523         "number".to_string()
524     }
525 
is_typeof<Other: Value>(env: Env, other: Other) -> bool526     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
527         unsafe { neon_runtime::tag::is_number(env.to_raw(), other.to_raw()) }
528     }
529 }
530 
531 /// A JavaScript object.
532 #[repr(C)]
533 #[derive(Clone, Copy)]
534 pub struct JsObject(raw::Local);
535 
536 impl Value for JsObject {}
537 
538 impl Managed for JsObject {
to_raw(self) -> raw::Local539     fn to_raw(self) -> raw::Local {
540         self.0
541     }
542 
from_raw(_: Env, h: raw::Local) -> Self543     fn from_raw(_: Env, h: raw::Local) -> Self {
544         JsObject(h)
545     }
546 }
547 
548 unsafe impl This for JsObject {
549     #[cfg(feature = "legacy-runtime")]
as_this(h: raw::Local) -> Self550     fn as_this(h: raw::Local) -> Self {
551         JsObject(h)
552     }
553 
554     #[cfg(feature = "napi-1")]
as_this(_env: Env, h: raw::Local) -> Self555     fn as_this(_env: Env, h: raw::Local) -> Self {
556         JsObject(h)
557     }
558 }
559 
560 impl ValueInternal for JsObject {
name() -> String561     fn name() -> String {
562         "object".to_string()
563     }
564 
is_typeof<Other: Value>(env: Env, other: Other) -> bool565     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
566         unsafe { neon_runtime::tag::is_object(env.to_raw(), other.to_raw()) }
567     }
568 }
569 
570 impl Object for JsObject {}
571 
572 impl JsObject {
new<'a, C: Context<'a>>(c: &mut C) -> Handle<'a, JsObject>573     pub fn new<'a, C: Context<'a>>(c: &mut C) -> Handle<'a, JsObject> {
574         JsObject::new_internal(c.env())
575     }
576 
new_internal<'a>(env: Env) -> Handle<'a, JsObject>577     pub(crate) fn new_internal<'a>(env: Env) -> Handle<'a, JsObject> {
578         JsObject::build(|out| unsafe { neon_runtime::object::new(out, env.to_raw()) })
579     }
580 
build<'a, F: FnOnce(&mut raw::Local)>(init: F) -> Handle<'a, JsObject>581     pub(crate) fn build<'a, F: FnOnce(&mut raw::Local)>(init: F) -> Handle<'a, JsObject> {
582         unsafe {
583             let mut local: raw::Local = std::mem::zeroed();
584             init(&mut local);
585             Handle::new_internal(JsObject(local))
586         }
587     }
588 }
589 
590 /// A JavaScript array object, i.e. a value for which `Array.isArray`
591 /// would return `true`.
592 #[repr(C)]
593 #[derive(Clone, Copy)]
594 pub struct JsArray(raw::Local);
595 
596 impl JsArray {
new<'a, C: Context<'a>>(cx: &mut C, len: u32) -> Handle<'a, JsArray>597     pub fn new<'a, C: Context<'a>>(cx: &mut C, len: u32) -> Handle<'a, JsArray> {
598         JsArray::new_internal(cx.env(), len)
599     }
600 
new_internal<'a>(env: Env, len: u32) -> Handle<'a, JsArray>601     pub(crate) fn new_internal<'a>(env: Env, len: u32) -> Handle<'a, JsArray> {
602         unsafe {
603             let mut local: raw::Local = std::mem::zeroed();
604             neon_runtime::array::new(&mut local, env.to_raw(), len);
605             Handle::new_internal(JsArray(local))
606         }
607     }
608 
to_vec<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult<Vec<Handle<'a, JsValue>>>609     pub fn to_vec<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult<Vec<Handle<'a, JsValue>>> {
610         let mut result = Vec::with_capacity(self.len_inner(cx.env()) as usize);
611         let mut i = 0;
612         loop {
613             // Since getting a property can trigger arbitrary code,
614             // we have to re-check the length on every iteration.
615             if i >= self.len_inner(cx.env()) {
616                 return Ok(result);
617             }
618             result.push(self.get(cx, i)?);
619             i += 1;
620         }
621     }
622 
len_inner(self, env: Env) -> u32623     fn len_inner(self, env: Env) -> u32 {
624         unsafe { neon_runtime::array::len(env.to_raw(), self.to_raw()) }
625     }
626 
627     #[cfg(feature = "legacy-runtime")]
len(self) -> u32628     pub fn len(self) -> u32 {
629         self.len_inner(Env::current())
630     }
631 
632     #[cfg(feature = "napi-1")]
len<'a, C: Context<'a>>(self, cx: &mut C) -> u32633     pub fn len<'a, C: Context<'a>>(self, cx: &mut C) -> u32 {
634         self.len_inner(cx.env())
635     }
636 
637     #[cfg(feature = "legacy-runtime")]
is_empty(self) -> bool638     pub fn is_empty(self) -> bool {
639         self.len() == 0
640     }
641 
642     #[cfg(feature = "napi-1")]
is_empty<'a, C: Context<'a>>(self, cx: &mut C) -> bool643     pub fn is_empty<'a, C: Context<'a>>(self, cx: &mut C) -> bool {
644         self.len(cx) == 0
645     }
646 }
647 
648 impl Value for JsArray {}
649 
650 impl Managed for JsArray {
to_raw(self) -> raw::Local651     fn to_raw(self) -> raw::Local {
652         self.0
653     }
654 
from_raw(_: Env, h: raw::Local) -> Self655     fn from_raw(_: Env, h: raw::Local) -> Self {
656         JsArray(h)
657     }
658 }
659 
660 impl ValueInternal for JsArray {
name() -> String661     fn name() -> String {
662         "Array".to_string()
663     }
664 
is_typeof<Other: Value>(env: Env, other: Other) -> bool665     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
666         unsafe { neon_runtime::tag::is_array(env.to_raw(), other.to_raw()) }
667     }
668 }
669 
670 impl Object for JsArray {}
671 
672 /// A JavaScript function object.
673 #[repr(C)]
674 #[derive(Clone, Copy)]
675 pub struct JsFunction<T: Object = JsObject> {
676     raw: raw::Local,
677     marker: PhantomData<T>,
678 }
679 
680 impl<T: Object> Object for JsFunction<T> {}
681 
682 // Maximum number of function arguments in V8.
683 const V8_ARGC_LIMIT: usize = 65535;
684 
prepare_call<'a, 'b, C: Context<'a>, A>( cx: &mut C, args: &mut [Handle<'b, A>], ) -> NeonResult<(i32, *mut c_void)> where A: Value + 'b,685 unsafe fn prepare_call<'a, 'b, C: Context<'a>, A>(
686     cx: &mut C,
687     args: &mut [Handle<'b, A>],
688 ) -> NeonResult<(i32, *mut c_void)>
689 where
690     A: Value + 'b,
691 {
692     let argv = args.as_mut_ptr();
693     let argc = args.len();
694     if argc > V8_ARGC_LIMIT {
695         return cx.throw_range_error("too many arguments");
696     }
697     Ok((argc as i32, argv as *mut c_void))
698 }
699 
700 impl JsFunction {
new<'a, C, U>( cx: &mut C, f: fn(FunctionContext) -> JsResult<U>, ) -> JsResult<'a, JsFunction> where C: Context<'a>, U: Value,701     pub fn new<'a, C, U>(
702         cx: &mut C,
703         f: fn(FunctionContext) -> JsResult<U>,
704     ) -> JsResult<'a, JsFunction>
705     where
706         C: Context<'a>,
707         U: Value,
708     {
709         build(cx.env(), |out| {
710             let env = cx.env().to_raw();
711             unsafe {
712                 let callback = FunctionCallback(f).into_c_callback();
713                 neon_runtime::fun::new(out, env, callback)
714             }
715         })
716     }
717 }
718 
719 impl<CL: Object> JsFunction<CL> {
call<'a, 'b, C: Context<'a>, T, A, AS>( self, cx: &mut C, this: Handle<'b, T>, args: AS, ) -> JsResult<'a, JsValue> where T: Value, A: Value + 'b, AS: IntoIterator<Item = Handle<'b, A>>,720     pub fn call<'a, 'b, C: Context<'a>, T, A, AS>(
721         self,
722         cx: &mut C,
723         this: Handle<'b, T>,
724         args: AS,
725     ) -> JsResult<'a, JsValue>
726     where
727         T: Value,
728         A: Value + 'b,
729         AS: IntoIterator<Item = Handle<'b, A>>,
730     {
731         let mut args = args.into_iter().collect::<SmallVec<[_; 8]>>();
732         let (argc, argv) = unsafe { prepare_call(cx, &mut args) }?;
733         let env = cx.env().to_raw();
734         build(cx.env(), |out| unsafe {
735             neon_runtime::fun::call(out, env, self.to_raw(), this.to_raw(), argc, argv)
736         })
737     }
738 
construct<'a, 'b, C: Context<'a>, A, AS>(self, cx: &mut C, args: AS) -> JsResult<'a, CL> where A: Value + 'b, AS: IntoIterator<Item = Handle<'b, A>>,739     pub fn construct<'a, 'b, C: Context<'a>, A, AS>(self, cx: &mut C, args: AS) -> JsResult<'a, CL>
740     where
741         A: Value + 'b,
742         AS: IntoIterator<Item = Handle<'b, A>>,
743     {
744         let mut args = args.into_iter().collect::<SmallVec<[_; 8]>>();
745         let (argc, argv) = unsafe { prepare_call(cx, &mut args) }?;
746         let env = cx.env().to_raw();
747         build(cx.env(), |out| unsafe {
748             neon_runtime::fun::construct(out, env, self.to_raw(), argc, argv)
749         })
750     }
751 }
752 
753 impl<T: Object> Value for JsFunction<T> {}
754 
755 impl<T: Object> Managed for JsFunction<T> {
to_raw(self) -> raw::Local756     fn to_raw(self) -> raw::Local {
757         self.raw
758     }
759 
from_raw(_: Env, h: raw::Local) -> Self760     fn from_raw(_: Env, h: raw::Local) -> Self {
761         JsFunction {
762             raw: h,
763             marker: PhantomData,
764         }
765     }
766 }
767 
768 impl<T: Object> ValueInternal for JsFunction<T> {
name() -> String769     fn name() -> String {
770         "function".to_string()
771     }
772 
is_typeof<Other: Value>(env: Env, other: Other) -> bool773     fn is_typeof<Other: Value>(env: Env, other: Other) -> bool {
774         unsafe { neon_runtime::tag::is_function(env.to_raw(), other.to_raw()) }
775     }
776 }
777