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}