nodex_api/value/
buffer.rs

1use crate::{api, prelude::*};
2use std::{mem::MaybeUninit, os::raw::c_char};
3
4#[derive(Copy, Clone, Debug)]
5pub struct JsBuffer<const N: usize>(pub(crate) JsValue);
6
7impl<const N: usize> JsBuffer<N> {
8    pub(crate) fn from_value(value: JsValue) -> JsBuffer<N> {
9        JsBuffer(value)
10    }
11
12    /// This API allocates a node::Buffer object. While this is still a fully-supported data
13    /// structure, in most cases using a TypedArray will suffice.
14    pub fn create(env: NapiEnv) -> NapiResult<JsBuffer<N>> {
15        let buffer = napi_call!(=napi_create_buffer, env, N, std::ptr::null_mut());
16        Ok(JsBuffer::<N>::from_raw(env, buffer))
17    }
18
19    /// This API allocates a node::Buffer object and initializes it with data copied from the
20    /// passed-in buffer. While this is still a fully-supported data structure, in most cases using
21    /// a TypedArray will suffice.
22    pub fn create_copy(env: NapiEnv, data: [u8; N]) -> NapiResult<JsBuffer<N>> {
23        let buffer = napi_call!(
24            =napi_create_buffer_copy,
25            env,
26            N,
27            data.as_ref().as_ptr() as _,
28            std::ptr::null_mut(),
29        );
30        Ok(JsBuffer::<N>::from_raw(env, buffer))
31    }
32
33    // pub fn create_external(
34    //     env: NapiEnv,
35    //     data: impl AsRef<[u8]>,
36    //     finalizer: impl FnOnce(NapiEnv, [u8; N]) -> NapiResult<()> + 'static,
37    // ) -> NapiResult<JsBuffer<N>>
38    // {
39    //     type FnOnceBoxed<const N: usize> = Box<dyn FnOnce(NapiEnv, [u8; N]) -> NapiResult<()>>;
40    //
41    //     unsafe extern "C" fn finalize<const N: usize>(
42    //         env: NapiEnv,
43    //         data: DataPointer,
44    //         hint: DataPointer,
45    //     ) {
46    //         let ext: [u8; N] = *(data as *const [u8; N]);
47    //         let finalizer: Box<FnOnceBoxed::<N>> = Box::from_raw(hint as _);
48    //         if let Err(e) = finalizer(env, ext) {
49    //             log::error!("JsExternal::<T>::finalize: {}", e);
50    //         }
51    //         std::ptr::drop_in_place(data as *mut [u8; N]);
52    //     }
53    //
54    //     let finalizer: Box<FnOnceBoxed::<N>> = Box::new(Box::new(finalizer));
55    //     let data = std::mem::ManuallyDrop::new([10; 10]);
56    //
57    //     let buffer = napi_call!(
58    //         =napi_create_external_buffer,
59    //         env,
60    //         N,
61    //         data.as_ptr() as DataPointer,
62    //         Some(finalize::<N>),
63    //         Box::into_raw(finalizer) as DataPointer,
64    //     );
65    //
66    //     Ok(JsBuffer::from_raw(env, buffer))
67    // }
68
69    /// Get the underlaying array
70    pub fn get(&self) -> NapiResult<&[u8]> {
71        let mut data = MaybeUninit::uninit();
72        let length = napi_call!(=napi_get_buffer_info, self.env(), self.raw(), data.as_mut_ptr());
73        if length != N {
74            return Err(NapiStatus::InvalidArg);
75        }
76
77        unsafe {
78            let data = data.assume_init();
79            Ok(std::slice::from_raw_parts(data as *mut u8, N))
80        }
81    }
82
83    /// Get the underlaying array (mut)
84    pub fn get_mut(&mut self) -> NapiResult<&mut [u8]> {
85        let mut data = MaybeUninit::uninit();
86        let length = napi_call!(=napi_get_buffer_info, self.env(), self.raw(), data.as_mut_ptr());
87        if length != N {
88            return Err(NapiStatus::InvalidArg);
89        }
90
91        unsafe {
92            let data = data.assume_init();
93            Ok(std::slice::from_raw_parts_mut(data as *mut u8, N))
94        }
95    }
96
97    /// The length of current buffer.
98    pub const fn len(&self) -> usize {
99        N
100    }
101
102    /// The buffer is empty
103    pub const fn is_empty(&self) -> bool {
104        N == 0
105    }
106}
107
108impl<const N: usize> NapiValueT for JsBuffer<N> {
109    fn from_raw(env: NapiEnv, raw: napi_value) -> JsBuffer<N> {
110        JsBuffer(JsValue(env, raw))
111    }
112
113    fn value(&self) -> JsValue {
114        self.0
115    }
116}
117
118impl<const N: usize> std::ops::Index<usize> for JsBuffer<N> {
119    type Output = u8;
120    fn index(&self, idx: usize) -> &Self::Output {
121        &self.get().unwrap()[idx]
122    }
123}
124
125impl<const N: usize> NapiValueCheck for JsBuffer<N> {
126    fn check(&self) -> NapiResult<bool> {
127        Ok(napi_call!(=napi_is_buffer, self.env(), self.raw()))
128    }
129}