Skip to main content

onepassword_sys/
buffer.rs

1use core::{ffi, fmt::Display, ptr::NonNull};
2
3use crate::util;
4
5use super::errors::CallStatus;
6
7#[cfg_attr(windows, link(name = "op_uniffi_core", kind = "raw-dylib"))]
8#[cfg_attr(not(windows), link(name = "op_uniffi_core"))]
9unsafe extern "C" {
10    #[link_name = "ffi_op_uniffi_core_rustbuffer_alloc"]
11    unsafe fn rustbuffer_alloc(size: u32, status: *mut CallStatus) -> RustBuffer;
12    #[expect(dead_code)]
13    #[link_name = "ffi_op_uniffi_core_rustbuffer_from_bytes"]
14    unsafe fn rustbuffer_from_bytes(bytes: ForeignBytes, status: *mut CallStatus) -> RustBuffer;
15    #[link_name = "ffi_op_uniffi_core_rustbuffer_free"]
16    unsafe fn rustbuffer_free(buffer: RustBuffer, status: *mut CallStatus);
17    #[link_name = "ffi_op_uniffi_core_rustbuffer_reserve"]
18    unsafe fn rustbuffer_reserve(
19        buffer: RustBuffer,
20        additional: u32,
21        status: *mut CallStatus,
22    ) -> RustBuffer;
23}
24
25#[repr(C)]
26struct ForeignBytes {
27    len: u32,
28    data: *const ffi::c_char,
29}
30
31impl<T: AsRef<[u8]>> From<T> for ForeignBytes {
32    fn from(value: T) -> Self {
33        let slice = value.as_ref();
34        let data = slice.as_ptr().cast();
35
36        Self {
37            data,
38            len: slice.len() as _,
39        }
40    }
41}
42
43#[repr(C)]
44#[derive(Debug, Default)]
45pub struct RustBuffer {
46    capacity: u32,
47    pub len: u32,
48    data: Option<NonNull<ffi::c_char>>,
49}
50
51impl Display for RustBuffer {
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53        if self.data.is_none() {
54            return f.write_str("");
55        };
56
57        match core::str::from_utf8(self.as_ref()) {
58            Ok(str) => f.write_str(str),
59            Err(_) => f.write_str(&String::from_utf8_lossy(self.as_ref())),
60        }
61    }
62}
63
64impl RustBuffer {
65    pub fn with_capacity(size: u32) -> RustBuffer {
66        let Ok(mut buffer) = unsafe { util::rust_call!(rustbuffer_alloc, size) };
67        buffer.len = 0;
68        buffer
69    }
70
71    pub fn reserve(&mut self, additional: u32) {
72        let buffer = core::mem::take(self);
73        let Ok(new_buf) = unsafe { util::rust_call!(rustbuffer_reserve, buffer, additional) };
74        *self = new_buf;
75    }
76
77    pub fn write(&mut self, buf: &[u8]) -> usize {
78        if self.len + (buf.len() as u32) > self.capacity {
79            self.reserve(buf.len() as u32);
80        }
81
82        let current_len = self.len as usize;
83        let pointer = self.data.expect("buffer should not be empty");
84
85        for (i, byte) in buf.iter().copied().enumerate() {
86            unsafe { pointer.add(current_len + i).write(byte as _) };
87        }
88
89        self.len = (current_len + buf.len()) as u32;
90        buf.len()
91    }
92}
93
94impl From<&str> for RustBuffer {
95    fn from(value: &str) -> Self {
96        let mut buffer = Self::with_capacity(value.len() as _);
97        buffer.write(value.as_bytes());
98        buffer
99    }
100}
101
102impl Drop for RustBuffer {
103    fn drop(&mut self) {
104        if self.data.is_none() {
105            return;
106        }
107
108        let Ok(_) = unsafe { util::rust_call!(rustbuffer_free, core::mem::take(self)) };
109    }
110}
111
112impl AsRef<[u8]> for RustBuffer {
113    fn as_ref(&self) -> &[u8] {
114        let Some(data) = self.data else { return &[] };
115        unsafe { core::slice::from_raw_parts(data.as_ptr().cast_const().cast(), self.len as _) }
116    }
117}
118
119impl AsMut<[u8]> for RustBuffer {
120    fn as_mut(&mut self) -> &mut [u8] {
121        let Some(data) = self.data else {
122            return &mut [];
123        };
124
125        unsafe { core::slice::from_raw_parts_mut(data.as_ptr().cast(), self.len as _) }
126    }
127}
128
129#[cfg(feature = "std")]
130impl std::io::Write for RustBuffer {
131    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
132        if self.len + (buf.len() as u32) > self.capacity {
133            self.reserve(buf.len() as u32);
134        }
135
136        let current_len = self.len as usize;
137        let pointer = self.data.expect("buffer should not be empty");
138
139        for (i, byte) in buf.iter().copied().enumerate() {
140            unsafe { pointer.add(current_len + i).write(byte as _) };
141        }
142
143        self.len = (current_len + buf.len()) as u32;
144        Ok(buf.len())
145    }
146
147    fn flush(&mut self) -> std::io::Result<()> {
148        Ok(())
149    }
150}