Skip to main content

deno_napi/
value.rs

1// Copyright 2018-2026 the Deno authors. MIT license.
2
3use std::mem::transmute;
4use std::ops::Deref;
5use std::os::raw::c_void;
6use std::ptr::NonNull;
7
8use deno_core::v8;
9
10/// An FFI-opaque, nullable wrapper around v8::Local<v8::Value>.
11/// rusty_v8 Local handle cannot be empty but napi_value can be.
12#[repr(transparent)]
13#[derive(Clone, Copy, Debug)]
14pub struct NapiValue<'s>(
15  Option<NonNull<v8::Value>>,
16  std::marker::PhantomData<&'s ()>,
17);
18
19pub type napi_value<'s> = NapiValue<'s>;
20
21impl<'s> Deref for napi_value<'s> {
22  type Target = Option<v8::Local<'s, v8::Value>>;
23  fn deref(&self) -> &Self::Target {
24    // SAFETY: It is safe to transmute `Option<NonNull<T>>` to `Option<*const T>`.
25    //         v8::Local guarantees that *const T is not null but napi_value *can* be null.
26    unsafe { transmute::<&Self, &Self::Target>(self) }
27  }
28}
29
30impl<'s, T> From<v8::Local<'s, T>> for napi_value<'s>
31where
32  v8::Local<'s, T>: Into<v8::Local<'s, v8::Value>>,
33{
34  fn from(v: v8::Local<'s, T>) -> Self {
35    Self(Some(NonNull::from(&*v.into())), std::marker::PhantomData)
36  }
37}
38
39impl<'s, T> From<Option<v8::Local<'s, T>>> for napi_value<'s>
40where
41  v8::Local<'s, T>: Into<v8::Local<'s, v8::Value>>,
42{
43  fn from(v: Option<v8::Local<'s, T>>) -> Self {
44    if let Some(v) = v {
45      NapiValue::from(v)
46    } else {
47      Self(None, std::marker::PhantomData)
48    }
49  }
50}
51
52const _: () = {
53  assert!(
54    std::mem::size_of::<napi_value>() == std::mem::size_of::<*mut c_void>()
55  );
56  // Assert "nullable pointer optimization" on napi_value
57  unsafe {
58    type Src<'a> = napi_value<'a>;
59    type Dst = usize;
60    assert!(std::mem::size_of::<Src>() == std::mem::size_of::<Dst>());
61    union Transmute<'a> {
62      src: Src<'a>,
63      dst: Dst,
64    }
65    Transmute {
66      src: NapiValue(None, std::marker::PhantomData),
67    }
68    .dst
69  };
70};