1use std::convert::TryFrom;
2#[cfg(feature = "napi5")]
3use std::ffi::c_void;
4use std::ffi::CString;
5use std::ptr;
6
7use crate::{
8 bindgen_runtime::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
9 check_status, sys, type_of, Callback, Error, Result, Status, ValueType,
10};
11
12#[cfg(feature = "serde-json")]
13mod de;
14#[cfg(feature = "serde-json")]
15mod ser;
16
17mod arraybuffer;
18#[cfg(feature = "napi6")]
19mod bigint;
20mod boolean;
21mod buffer;
22#[cfg(feature = "napi5")]
23mod date;
24#[cfg(feature = "napi4")]
25mod deferred;
26mod either;
27mod escapable_handle_scope;
28mod function;
29mod global;
30mod number;
31mod object;
32mod object_property;
33mod string;
34mod tagged_object;
35mod undefined;
36mod value;
37mod value_ref;
38
39pub use arraybuffer::*;
40#[cfg(feature = "napi6")]
41pub use bigint::JsBigInt;
42pub use boolean::JsBoolean;
43pub use buffer::*;
44#[cfg(feature = "napi5")]
45pub use date::*;
46#[cfg(feature = "serde-json")]
47pub use de::De;
48#[cfg(feature = "napi4")]
49pub use deferred::*;
50pub use either::Either;
51pub use escapable_handle_scope::EscapableHandleScope;
52pub use function::JsFunction;
53pub use global::*;
54pub use number::JsNumber;
55pub use object::*;
56pub use object_property::*;
57#[cfg(feature = "serde-json")]
58pub use ser::Ser;
59pub use string::*;
60pub(crate) use tagged_object::TaggedObject;
61pub use undefined::JsUndefined;
62pub(crate) use value::Value;
63pub use value_ref::*;
64
65// Value types
66
67pub struct JsUnknown(pub(crate) Value);
68
69#[derive(Clone, Copy)]
70pub struct JsNull(pub(crate) Value);
71
72impl TypeName for JsNull {
73 fn type_name() -> &'static str {
74 "null"
75 }
76
77 fn value_type() -> ValueType {
78 ValueType::Null
79 }
80}
81
82impl ValidateNapiValue for JsNull {}
83
84#[derive(Clone, Copy)]
85pub struct JsSymbol(pub(crate) Value);
86
87impl TypeName for JsSymbol {
88 fn type_name() -> &'static str {
89 "symbol"
90 }
91
92 fn value_type() -> ValueType {
93 ValueType::Symbol
94 }
95}
96
97impl ValidateNapiValue for JsSymbol {}
98
99#[deprecated(since = "3.0.0", note = "Please use `External` instead")]
100pub struct JsExternal(pub(crate) Value);
101
102impl TypeName for JsExternal {
103 fn type_name() -> &'static str {
104 "external"
105 }
106
107 fn value_type() -> ValueType {
108 ValueType::External
109 }
110}
111
112impl ValidateNapiValue for JsExternal {}
113
114macro_rules! impl_napi_value_trait {
115 ($js_value:ident, $value_type:ident) => {
116 impl NapiValue for $js_value {
117 unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<$js_value> {
118 let value_type = type_of!(env, value)?;
119 if value_type != $value_type {
120 Err(Error::new(
121 Status::InvalidArg,
122 format!("expect {:?}, got: {:?}", $value_type, value_type),
123 ))
124 } else {
125 Ok($js_value(Value {
126 env,
127 value,
128 value_type: $value_type,
129 }))
130 }
131 }
132
133 unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> $js_value {
134 $js_value(Value {
135 env,
136 value,
137 value_type: $value_type,
138 })
139 }
140 }
141
142 impl NapiRaw for $js_value {
143 unsafe fn raw(&self) -> sys::napi_value {
144 self.0.value
145 }
146 }
147
148 impl<'env> NapiRaw for &'env $js_value {
149 unsafe fn raw(&self) -> sys::napi_value {
150 self.0.value
151 }
152 }
153
154 impl TryFrom<JsUnknown> for $js_value {
155 type Error = Error;
156 fn try_from(value: JsUnknown) -> Result<$js_value> {
157 unsafe { $js_value::from_raw(value.0.env, value.0.value) }
158 }
159 }
160 };
161}
162
163macro_rules! impl_js_value_methods {
164 ($js_value:ident) => {
165 impl $js_value {
166 pub fn into_unknown(self) -> JsUnknown {
167 unsafe { JsUnknown::from_raw_unchecked(self.0.env, self.0.value) }
168 }
169
170 pub fn coerce_to_bool(self) -> Result<JsBoolean> {
171 let mut new_raw_value = ptr::null_mut();
172 check_status!(unsafe {
173 sys::napi_coerce_to_bool(self.0.env, self.0.value, &mut new_raw_value)
174 })?;
175 Ok(JsBoolean(Value {
176 env: self.0.env,
177 value: new_raw_value,
178 value_type: ValueType::Boolean,
179 }))
180 }
181
182 pub fn coerce_to_number(self) -> Result<JsNumber> {
183 let mut new_raw_value = ptr::null_mut();
184 check_status!(unsafe {
185 sys::napi_coerce_to_number(self.0.env, self.0.value, &mut new_raw_value)
186 })?;
187 Ok(JsNumber(Value {
188 env: self.0.env,
189 value: new_raw_value,
190 value_type: ValueType::Number,
191 }))
192 }
193
194 pub fn coerce_to_string(self) -> Result<JsString> {
195 let mut new_raw_value = ptr::null_mut();
196 check_status!(unsafe {
197 sys::napi_coerce_to_string(self.0.env, self.0.value, &mut new_raw_value)
198 })?;
199 Ok(JsString(Value {
200 env: self.0.env,
201 value: new_raw_value,
202 value_type: ValueType::String,
203 }))
204 }
205
206 pub fn coerce_to_object(self) -> Result<JsObject> {
207 let mut new_raw_value = ptr::null_mut();
208 check_status!(unsafe {
209 sys::napi_coerce_to_object(self.0.env, self.0.value, &mut new_raw_value)
210 })?;
211 Ok(JsObject(Value {
212 env: self.0.env,
213 value: new_raw_value,
214 value_type: ValueType::Object,
215 }))
216 }
217
218 #[cfg(feature = "napi5")]
219 pub fn is_date(&self) -> Result<bool> {
220 let mut is_date = true;
221 check_status!(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?;
222 Ok(is_date)
223 }
224
225 pub fn is_promise(&self) -> Result<bool> {
226 let mut is_promise = true;
227 check_status!(unsafe { sys::napi_is_promise(self.0.env, self.0.value, &mut is_promise) })?;
228 Ok(is_promise)
229 }
230
231 pub fn is_error(&self) -> Result<bool> {
232 let mut result = false;
233 check_status!(unsafe { sys::napi_is_error(self.0.env, self.0.value, &mut result) })?;
234 Ok(result)
235 }
236
237 pub fn is_typedarray(&self) -> Result<bool> {
238 let mut result = false;
239 check_status!(unsafe { sys::napi_is_typedarray(self.0.env, self.0.value, &mut result) })?;
240 Ok(result)
241 }
242
243 pub fn is_dataview(&self) -> Result<bool> {
244 let mut result = false;
245 check_status!(unsafe { sys::napi_is_dataview(self.0.env, self.0.value, &mut result) })?;
246 Ok(result)
247 }
248
249 pub fn is_array(&self) -> Result<bool> {
250 let mut is_array = false;
251 check_status!(unsafe { sys::napi_is_array(self.0.env, self.0.value, &mut is_array) })?;
252 Ok(is_array)
253 }
254
255 pub fn is_buffer(&self) -> Result<bool> {
256 let mut is_buffer = false;
257 check_status!(unsafe { sys::napi_is_buffer(self.0.env, self.0.value, &mut is_buffer) })?;
258 Ok(is_buffer)
259 }
260
261 pub fn instanceof<Constructor>(&self, constructor: Constructor) -> Result<bool>
262 where
263 Constructor: NapiRaw,
264 {
265 let mut result = false;
266 check_status!(unsafe {
267 sys::napi_instanceof(self.0.env, self.0.value, constructor.raw(), &mut result)
268 })?;
269 Ok(result)
270 }
271 }
272 };
273}
274
275macro_rules! impl_object_methods {
276 ($js_value:ident) => {
277 impl $js_value {
278 pub fn set_property<K, V>(&mut self, key: K, value: V) -> Result<()>
279 where
280 K: NapiRaw,
281 V: NapiRaw,
282 {
283 check_status!(unsafe {
284 sys::napi_set_property(self.0.env, self.0.value, key.raw(), value.raw())
285 })
286 }
287
288 pub fn get_property<K, T>(&self, key: K) -> Result<T>
289 where
290 K: NapiRaw,
291 T: NapiValue,
292 {
293 let mut raw_value = ptr::null_mut();
294 check_status!(unsafe {
295 sys::napi_get_property(self.0.env, self.0.value, key.raw(), &mut raw_value)
296 })?;
297 unsafe { T::from_raw(self.0.env, raw_value) }
298 }
299
300 pub fn get_property_unchecked<K, T>(&self, key: K) -> Result<T>
301 where
302 K: NapiRaw,
303 T: NapiValue,
304 {
305 let mut raw_value = ptr::null_mut();
306 check_status!(unsafe {
307 sys::napi_get_property(self.0.env, self.0.value, key.raw(), &mut raw_value)
308 })?;
309 Ok(unsafe { T::from_raw_unchecked(self.0.env, raw_value) })
310 }
311
312 pub fn set_named_property<T>(&mut self, name: &str, value: T) -> Result<()>
313 where
314 T: ToNapiValue,
315 {
316 let key = CString::new(name)?;
317 check_status!(unsafe {
318 sys::napi_set_named_property(
319 self.0.env,
320 self.0.value,
321 key.as_ptr(),
322 T::to_napi_value(self.0.env, value)?,
323 )
324 })
325 }
326
327 pub fn create_named_method(&mut self, name: &str, function: Callback) -> Result<()> {
328 let mut js_function = ptr::null_mut();
329 let len = name.len();
330 let name = CString::new(name)?;
331 check_status!(unsafe {
332 sys::napi_create_function(
333 self.0.env,
334 name.as_ptr(),
335 len,
336 Some(function),
337 ptr::null_mut(),
338 &mut js_function,
339 )
340 })?;
341 check_status!(
342 unsafe {
343 sys::napi_set_named_property(self.0.env, self.0.value, name.as_ptr(), js_function)
344 },
345 "create_named_method error"
346 )
347 }
348
349 pub fn get_named_property<T>(&self, name: &str) -> Result<T>
350 where
351 T: FromNapiValue + ValidateNapiValue,
352 {
353 let key = CString::new(name)?;
354 let mut raw_value = ptr::null_mut();
355 check_status!(
356 unsafe {
357 sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
358 },
359 "get_named_property error"
360 )?;
361 unsafe { <T as ValidateNapiValue>::validate(self.0.env, raw_value) }.map_err(
362 |mut err| {
363 err.reason = format!("Object property '{name}' type mismatch. {}", err.reason);
364 err
365 },
366 )?;
367 unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
368 }
369
370 pub fn get_named_property_unchecked<T>(&self, name: &str) -> Result<T>
371 where
372 T: FromNapiValue,
373 {
374 let key = CString::new(name)?;
375 let mut raw_value = ptr::null_mut();
376 check_status!(
377 unsafe {
378 sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
379 },
380 "get_named_property_unchecked error"
381 )?;
382 unsafe { <T as FromNapiValue>::from_napi_value(self.0.env, raw_value) }
383 }
384
385 pub fn has_named_property<N: AsRef<str>>(&self, name: N) -> Result<bool> {
386 let mut result = false;
387 let key = CString::new(name.as_ref())?;
388 check_status!(
389 unsafe {
390 sys::napi_has_named_property(self.0.env, self.0.value, key.as_ptr(), &mut result)
391 },
392 "napi_has_named_property error"
393 )?;
394 Ok(result)
395 }
396
397 pub fn delete_property<S>(&mut self, name: S) -> Result<bool>
398 where
399 S: NapiRaw,
400 {
401 let mut result = false;
402 check_status!(unsafe {
403 sys::napi_delete_property(self.0.env, self.0.value, name.raw(), &mut result)
404 })?;
405 Ok(result)
406 }
407
408 pub fn delete_named_property(&mut self, name: &str) -> Result<bool> {
409 let mut result = false;
410 let mut js_key = ptr::null_mut();
411 check_status!(unsafe {
412 sys::napi_create_string_utf8(self.0.env, name.as_ptr().cast(), name.len(), &mut js_key)
413 })?;
414 check_status!(unsafe {
415 sys::napi_delete_property(self.0.env, self.0.value, js_key, &mut result)
416 })?;
417 Ok(result)
418 }
419
420 pub fn has_own_property(&self, key: &str) -> Result<bool> {
421 let mut result = false;
422 let mut js_key = ptr::null_mut();
423 check_status!(unsafe {
424 sys::napi_create_string_utf8(self.0.env, key.as_ptr().cast(), key.len(), &mut js_key)
425 })?;
426 check_status!(unsafe {
427 sys::napi_has_own_property(self.0.env, self.0.value, js_key, &mut result)
428 })?;
429 Ok(result)
430 }
431
432 pub fn has_own_property_js<K>(&self, key: K) -> Result<bool>
433 where
434 K: NapiRaw,
435 {
436 let mut result = false;
437 check_status!(unsafe {
438 sys::napi_has_own_property(self.0.env, self.0.value, key.raw(), &mut result)
439 })?;
440 Ok(result)
441 }
442
443 pub fn has_property(&self, name: &str) -> Result<bool> {
444 let mut js_key = ptr::null_mut();
445 let mut result = false;
446 check_status!(unsafe {
447 sys::napi_create_string_utf8(self.0.env, name.as_ptr().cast(), name.len(), &mut js_key)
448 })?;
449 check_status!(unsafe {
450 sys::napi_has_property(self.0.env, self.0.value, js_key, &mut result)
451 })?;
452 Ok(result)
453 }
454
455 pub fn has_property_js<K>(&self, name: K) -> Result<bool>
456 where
457 K: NapiRaw,
458 {
459 let mut result = false;
460 check_status!(unsafe {
461 sys::napi_has_property(self.0.env, self.0.value, name.raw(), &mut result)
462 })?;
463 Ok(result)
464 }
465
466 pub fn get_property_names(&self) -> Result<JsObject> {
467 let mut raw_value = ptr::null_mut();
468 check_status!(unsafe {
469 sys::napi_get_property_names(self.0.env, self.0.value, &mut raw_value)
470 })?;
471 Ok(unsafe { JsObject::from_raw_unchecked(self.0.env, raw_value) })
472 }
473
474 /// <https://nodejs.org/api/n-api.html#n_api_napi_get_all_property_names>
475 /// return `Array` of property names
476 #[cfg(feature = "napi6")]
477 pub fn get_all_property_names(
478 &self,
479 mode: KeyCollectionMode,
480 filter: KeyFilter,
481 conversion: KeyConversion,
482 ) -> Result<JsObject> {
483 let mut properties_value = ptr::null_mut();
484 check_status!(unsafe {
485 sys::napi_get_all_property_names(
486 self.0.env,
487 self.0.value,
488 mode.into(),
489 filter.into(),
490 conversion.into(),
491 &mut properties_value,
492 )
493 })?;
494 Ok(unsafe { JsObject::from_raw_unchecked(self.0.env, properties_value) })
495 }
496
497 /// This returns the equivalent of `Object.getPrototypeOf` (which is not the same as the function's prototype property).
498 pub fn get_prototype<T>(&self) -> Result<T>
499 where
500 T: NapiValue,
501 {
502 let mut result = ptr::null_mut();
503 check_status!(unsafe { sys::napi_get_prototype(self.0.env, self.0.value, &mut result) })?;
504 unsafe { T::from_raw(self.0.env, result) }
505 }
506
507 pub fn get_prototype_unchecked<T>(&self) -> Result<T>
508 where
509 T: NapiValue,
510 {
511 let mut result = ptr::null_mut();
512 check_status!(unsafe { sys::napi_get_prototype(self.0.env, self.0.value, &mut result) })?;
513 Ok(unsafe { T::from_raw_unchecked(self.0.env, result) })
514 }
515
516 pub fn set_element<T>(&mut self, index: u32, value: T) -> Result<()>
517 where
518 T: NapiRaw,
519 {
520 check_status!(unsafe {
521 sys::napi_set_element(self.0.env, self.0.value, index, value.raw())
522 })
523 }
524
525 pub fn has_element(&self, index: u32) -> Result<bool> {
526 let mut result = false;
527 check_status!(unsafe {
528 sys::napi_has_element(self.0.env, self.0.value, index, &mut result)
529 })?;
530 Ok(result)
531 }
532
533 pub fn delete_element(&mut self, index: u32) -> Result<bool> {
534 let mut result = false;
535 check_status!(unsafe {
536 sys::napi_delete_element(self.0.env, self.0.value, index, &mut result)
537 })?;
538 Ok(result)
539 }
540
541 pub fn get_element<T>(&self, index: u32) -> Result<T>
542 where
543 T: NapiValue,
544 {
545 let mut raw_value = ptr::null_mut();
546 check_status!(unsafe {
547 sys::napi_get_element(self.0.env, self.0.value, index, &mut raw_value)
548 })?;
549 unsafe { T::from_raw(self.0.env, raw_value) }
550 }
551
552 pub fn get_element_unchecked<T>(&self, index: u32) -> Result<T>
553 where
554 T: NapiValue,
555 {
556 let mut raw_value = ptr::null_mut();
557 check_status!(unsafe {
558 sys::napi_get_element(self.0.env, self.0.value, index, &mut raw_value)
559 })?;
560 Ok(unsafe { T::from_raw_unchecked(self.0.env, raw_value) })
561 }
562
563 /// This method allows the efficient definition of multiple properties on a given object.
564 pub fn define_properties(&mut self, properties: &[Property]) -> Result<()> {
565 let properties_iter = properties.iter().map(|property| property.raw());
566 #[cfg(feature = "napi5")]
567 {
568 let mut closures = properties_iter
569 .clone()
570 .map(|p| p.data)
571 .filter(|data| !data.is_null())
572 .collect::<Vec<*mut std::ffi::c_void>>();
573 let len = Box::into_raw(Box::new(closures.len()));
574 check_status!(unsafe {
575 sys::napi_add_finalizer(
576 self.0.env,
577 self.0.value,
578 closures.as_mut_ptr().cast(),
579 Some(finalize_closures),
580 len.cast(),
581 ptr::null_mut(),
582 )
583 })?;
584 std::mem::forget(closures);
585 }
586 check_status!(unsafe {
587 sys::napi_define_properties(
588 self.0.env,
589 self.0.value,
590 properties.len(),
591 properties_iter
592 .collect::<Vec<sys::napi_property_descriptor>>()
593 .as_ptr(),
594 )
595 })
596 }
597
598 /// Perform `is_array` check before get the length
599 /// if `Object` is not array, `ArrayExpected` error returned
600 pub fn get_array_length(&self) -> Result<u32> {
601 if self.is_array()? != true {
602 return Err(Error::new(
603 Status::ArrayExpected,
604 "Object is not array".to_owned(),
605 ));
606 }
607 self.get_array_length_unchecked()
608 }
609
610 /// use this API if you can ensure this `Object` is `Array`
611 pub fn get_array_length_unchecked(&self) -> Result<u32> {
612 let mut length: u32 = 0;
613 check_status!(unsafe {
614 sys::napi_get_array_length(self.0.env, self.0.value, &mut length)
615 })?;
616 Ok(length)
617 }
618
619 #[cfg(feature = "napi8")]
620 pub fn freeze(&mut self) -> Result<()> {
621 check_status!(unsafe { sys::napi_object_freeze(self.0.env, self.0.value) })
622 }
623
624 #[cfg(feature = "napi8")]
625 pub fn seal(&mut self) -> Result<()> {
626 check_status!(unsafe { sys::napi_object_seal(self.0.env, self.0.value) })
627 }
628 }
629 };
630}
631
632pub trait NapiRaw {
633 #[allow(clippy::missing_safety_doc)]
634 unsafe fn raw(&self) -> sys::napi_value;
635}
636
637pub trait NapiValue: Sized + NapiRaw {
638 #[allow(clippy::missing_safety_doc)]
639 unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self>;
640
641 #[allow(clippy::missing_safety_doc)]
642 unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self;
643}
644
645impl_js_value_methods!(JsUnknown);
646impl_js_value_methods!(JsUndefined);
647impl_js_value_methods!(JsNull);
648impl_js_value_methods!(JsBoolean);
649impl_js_value_methods!(JsBuffer);
650impl_js_value_methods!(JsArrayBuffer);
651impl_js_value_methods!(JsTypedArray);
652impl_js_value_methods!(JsDataView);
653impl_js_value_methods!(JsNumber);
654impl_js_value_methods!(JsString);
655impl_js_value_methods!(JsObject);
656impl_js_value_methods!(JsGlobal);
657#[cfg(feature = "napi5")]
658impl_js_value_methods!(JsDate);
659impl_js_value_methods!(JsFunction);
660impl_js_value_methods!(JsExternal);
661impl_js_value_methods!(JsSymbol);
662impl_js_value_methods!(JsTimeout);
663impl_js_value_methods!(JSON);
664
665impl_object_methods!(JsObject);
666impl_object_methods!(JsBuffer);
667impl_object_methods!(JsArrayBuffer);
668impl_object_methods!(JsTypedArray);
669impl_object_methods!(JsDataView);
670impl_object_methods!(JsGlobal);
671impl_object_methods!(JSON);
672
673use ValueType::*;
674
675impl_napi_value_trait!(JsUndefined, Undefined);
676impl_napi_value_trait!(JsNull, Null);
677impl_napi_value_trait!(JsBoolean, Boolean);
678impl_napi_value_trait!(JsBuffer, Object);
679impl_napi_value_trait!(JsArrayBuffer, Object);
680impl_napi_value_trait!(JsTypedArray, Object);
681impl_napi_value_trait!(JsDataView, Object);
682impl_napi_value_trait!(JsNumber, Number);
683impl_napi_value_trait!(JsString, String);
684impl_napi_value_trait!(JsObject, Object);
685impl_napi_value_trait!(JsGlobal, Object);
686#[cfg(feature = "napi5")]
687impl_napi_value_trait!(JsDate, Object);
688impl_napi_value_trait!(JsTimeout, Object);
689impl_napi_value_trait!(JsFunction, Function);
690impl_napi_value_trait!(JsExternal, External);
691impl_napi_value_trait!(JsSymbol, Symbol);
692
693impl NapiValue for JsUnknown {
694 unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
695 Ok(JsUnknown(Value {
696 env,
697 value,
698 value_type: Unknown,
699 }))
700 }
701
702 unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
703 JsUnknown(Value {
704 env,
705 value,
706 value_type: Unknown,
707 })
708 }
709}
710
711impl NapiRaw for JsUnknown {
712 /// get raw js value ptr
713 unsafe fn raw(&self) -> sys::napi_value {
714 self.0.value
715 }
716}
717
718impl<'env> NapiRaw for &'env JsUnknown {
719 /// get raw js value ptr
720 unsafe fn raw(&self) -> sys::napi_value {
721 self.0.value
722 }
723}
724
725impl JsUnknown {
726 pub fn get_type(&self) -> Result<ValueType> {
727 type_of!(self.0.env, self.0.value)
728 }
729
730 /// # Safety
731 ///
732 /// This function should be called after `JsUnknown::get_type`
733 ///
734 /// And the `V` must be match with the return value of `get_type`
735 pub unsafe fn cast<V>(&self) -> V
736 where
737 V: NapiValue,
738 {
739 unsafe { V::from_raw_unchecked(self.0.env, self.0.value) }
740 }
741}
742
743#[cfg(feature = "napi5")]
744unsafe extern "C" fn finalize_closures(_env: sys::napi_env, data: *mut c_void, len: *mut c_void) {
745 let length: usize = *unsafe { Box::from_raw(len.cast()) };
746 let closures: Vec<*mut PropertyClosures> =
747 unsafe { Vec::from_raw_parts(ptr:data.cast(), length, capacity:length) };
748 for closure: *mut PropertyClosures in closures.into_iter() {
749 drop(unsafe { Box::from_raw(closure) });
750 }
751}
752