neon/sys/
buffer.rs

1#[cfg(feature = "external-buffers")]
2use std::os::raw::c_void;
3use std::{mem::MaybeUninit, slice};
4
5use super::{
6    bindings as napi,
7    raw::{Env, Local},
8};
9
10pub unsafe fn new(env: Env, len: usize) -> Result<Local, napi::Status> {
11    let (buf, bytes) = uninitialized(env, len)?;
12
13    std::ptr::write_bytes(bytes, 0, len);
14
15    Ok(buf)
16}
17
18pub unsafe fn uninitialized(env: Env, len: usize) -> Result<(Local, *mut u8), napi::Status> {
19    let mut buf = MaybeUninit::uninit();
20    let mut bytes = MaybeUninit::uninit();
21    let status = napi::create_buffer(env, len, bytes.as_mut_ptr(), buf.as_mut_ptr());
22
23    match status {
24        Err(err @ napi::Status::PendingException) => return Err(err),
25        status => status.unwrap(),
26    };
27
28    Ok((buf.assume_init(), bytes.assume_init().cast()))
29}
30
31#[cfg(feature = "external-buffers")]
32pub unsafe fn new_external<T>(env: Env, data: T) -> Local
33where
34    T: AsMut<[u8]> + Send,
35{
36    // Safety: Boxing could move the data; must box before grabbing a raw pointer
37    let mut data = Box::new(data);
38    let buf = data.as_mut().as_mut();
39    let length = buf.len();
40    let mut result = MaybeUninit::uninit();
41
42    napi::create_external_buffer(
43        env,
44        length,
45        buf.as_mut_ptr() as *mut _,
46        Some(drop_external::<T>),
47        Box::into_raw(data) as *mut _,
48        result.as_mut_ptr(),
49    )
50    .unwrap();
51
52    result.assume_init()
53}
54
55#[cfg(feature = "external-buffers")]
56unsafe extern "C" fn drop_external<T>(_env: Env, _data: *mut c_void, hint: *mut c_void) {
57    drop(Box::<T>::from_raw(hint as *mut _));
58}
59
60/// # Safety
61/// * Caller must ensure `env` and `buf` are valid
62/// * The lifetime `'a` does not exceed the lifetime of `Env` or `buf`
63pub unsafe fn as_mut_slice<'a>(env: Env, buf: Local) -> &'a mut [u8] {
64    let mut data = MaybeUninit::uninit();
65    let mut size = 0usize;
66
67    napi::get_buffer_info(env, buf, data.as_mut_ptr(), &mut size as *mut _).unwrap();
68
69    if size == 0 {
70        return &mut [];
71    }
72
73    slice::from_raw_parts_mut(data.assume_init().cast(), size)
74}
75
76/// # Safety
77/// * Caller must ensure `env` and `buf` are valid
78pub unsafe fn size(env: Env, buf: Local) -> usize {
79    let mut data = MaybeUninit::uninit();
80    let mut size = 0usize;
81
82    napi::get_buffer_info(env, buf, data.as_mut_ptr(), &mut size as *mut _).unwrap();
83
84    size
85}