onepassword_sys/
buffer.rs1use 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}