protobuf_native/
internal.rs
1#[cfg(unix)]
17use std::ffi::OsStr;
18use std::fmt;
19use std::io::{Read, Write};
20use std::marker::PhantomData;
21use std::mem::MaybeUninit;
22use std::os::raw::{c_char, c_int, c_void};
23#[cfg(unix)]
24use std::os::unix::prelude::OsStrExt;
25use std::path::Path;
26
27use cxx::kind::Trivial;
28use cxx::{type_id, ExternType};
29
30use crate::OperationFailedError;
31
32#[cxx::bridge]
37mod ffi {
38 extern "Rust" {
39 unsafe fn vec_u8_set_len(v: &mut Vec<u8>, new_len: usize);
40 }
41
42 unsafe extern "C++" {
43 include!("protobuf-native/src/internal.h");
44
45 #[namespace = "absl"]
46 #[cxx_name = "string_view"]
47 type StringView<'a> = crate::internal::StringView<'a>;
48
49 #[namespace = "protobuf_native::internal"]
50 fn string_view_from_bytes(bytes: &[u8]) -> StringView;
51 }
52}
53
54unsafe fn vec_u8_set_len(v: &mut Vec<u8>, new_len: usize) {
55 v.set_len(new_len)
56}
57
58#[derive(Debug, Copy, Clone)]
59#[repr(C)]
60pub struct StringView<'a> {
61 repr: MaybeUninit<[*const c_void; 2]>,
62 borrow: PhantomData<&'a [c_char]>,
63}
64
65impl<'a> From<&'a str> for StringView<'a> {
66 fn from(s: &'a str) -> StringView<'a> {
67 ffi::string_view_from_bytes(s.as_bytes())
68 }
69}
70
71impl<'a> From<ProtobufPath<'a>> for StringView<'a> {
72 fn from(path: ProtobufPath<'a>) -> StringView<'a> {
73 ffi::string_view_from_bytes(path.as_bytes())
74 }
75}
76
77unsafe impl<'a> ExternType for StringView<'a> {
78 type Id = type_id!("absl::string_view");
79 type Kind = Trivial;
80}
81
82#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
86pub struct CInt(pub c_int);
87
88impl CInt {
89 pub fn to_usize(self) -> Result<usize, OperationFailedError> {
90 usize::try_from(self.0).map_err(|_| OperationFailedError)
91 }
92
93 pub fn expect_usize(self) -> usize {
94 match self.to_usize() {
95 Ok(n) => n,
96 Err(_) => panic!("C int is not representible as a Rust usize: {}", self.0),
97 }
98 }
99
100 pub fn try_from<T>(value: T) -> Result<CInt, T::Error>
101 where
102 T: TryInto<c_int>,
103 {
104 value.try_into().map(CInt)
105 }
106
107 pub fn expect_from<T>(value: T) -> CInt
108 where
109 T: TryInto<c_int> + Copy + fmt::Display,
110 {
111 match CInt::try_from(value) {
112 Ok(n) => n,
113 Err(_) => panic!("value is not representable as a C int: {}", value),
114 }
115 }
116}
117
118unsafe impl ExternType for CInt {
119 type Id = type_id!("protobuf_native::internal::CInt");
120 type Kind = Trivial;
121}
122
123#[derive(Debug)]
124pub struct CVoid(pub c_void);
125
126unsafe impl ExternType for CVoid {
127 type Id = type_id!("protobuf_native::internal::CVoid");
128 type Kind = Trivial;
129}
130
131pub struct ReadAdaptor<'a>(pub &'a mut dyn Read);
134
135impl ReadAdaptor<'_> {
136 pub fn read(&mut self, buf: &mut [u8]) -> isize {
137 match self.0.read(buf) {
138 Ok(n) => n.try_into().expect("read bytes do not fit into isize"),
139 Err(_) => -1,
140 }
141 }
142}
143
144pub struct WriteAdaptor<'a>(pub &'a mut dyn Write);
145
146impl WriteAdaptor<'_> {
147 pub fn write(&mut self, buf: &[u8]) -> bool {
148 self.0.write_all(buf).as_status()
149 }
150}
151
152pub trait ResultExt {
154 fn as_status(&self) -> bool;
159}
160
161impl<T, E> ResultExt for Result<T, E> {
162 fn as_status(&self) -> bool {
163 match self {
164 Ok(_) => true,
165 Err(_) => false,
166 }
167 }
168}
169
170pub trait BoolExt {
172 fn as_result(self) -> Result<(), OperationFailedError>;
177}
178
179impl BoolExt for bool {
180 fn as_result(self) -> Result<(), OperationFailedError> {
181 match self {
182 true => Ok(()),
183 false => Err(OperationFailedError),
184 }
185 }
186}
187
188#[cfg(unix)]
201#[derive(Debug, Clone, Eq, PartialEq, Hash)]
202pub struct ProtobufPath<'a>(&'a Path);
203
204#[cfg(windows)]
205#[derive(Debug, Clone, Eq, PartialEq, Hash)]
206pub struct ProtobufPath<'a> {
207 inner: Vec<u8>,
208 _phantom: PhantomData<'a>,
209}
210
211#[cfg(unix)]
212impl<'a> ProtobufPath<'a> {
213 pub fn as_path(&self) -> impl AsRef<Path> + 'a {
214 self.0
215 }
216}
217
218#[cfg(unix)]
219impl<'a> From<&'a [u8]> for ProtobufPath<'a> {
220 fn from(p: &'a [u8]) -> ProtobufPath<'a> {
221 ProtobufPath(Path::new(OsStr::from_bytes(p)))
222 }
223}
224
225#[cfg(unix)]
226impl<'a> From<&'a Path> for ProtobufPath<'a> {
227 fn from(p: &'a Path) -> ProtobufPath<'a> {
228 ProtobufPath(p)
229 }
230}
231
232#[cfg(unix)]
233impl<'a> ProtobufPath<'a> {
234 pub fn as_bytes(&self) -> &'a [u8] {
235 self.0.as_os_str().as_bytes()
236 }
237}
238
239#[cfg(windows)]
240impl<'a> ProtobufPath<'a> {
241 pub fn as_path(&self) -> impl AsRef<Path> {
242 PathBuf::from(String::from_utf8_lossy(self.inner))
243 }
244}
245
246#[cfg(windows)]
247impl<'a> From<&'a [u8]> for ProtobufPath<'static> {
248 fn from(p: &'a [u8]) -> ProtobufPath<'static> {
249 ProtobufPath {
250 inner: p.to_vec(),
251 _phantom: PhantomData,
252 }
253 }
254}
255
256#[cfg(windows)]
257impl<'a> From<Path> for ProtobufPath<'a> {
258 fn from(p: Path) -> ProtobufPath<'a> {
259 ProtobufPath {
260 inner: p.to_string_lossy().into_owned().into_bytes(),
261 _phantom: PhantomData,
262 }
263 }
264}
265
266#[cfg(windows)]
267impl<'a> ProtobufPath<'a> {
268 pub fn as_bytes(&self) -> &'a [u8] {
269 &self.inner
270 }
271}
272
273macro_rules! unsafe_ffi_conversions {
274 ($ty:ty) => {
275 #[allow(dead_code)]
276 pub(crate) unsafe fn from_ffi_owned(from: *mut $ty) -> Pin<Box<Self>> {
277 std::mem::transmute(from)
278 }
279
280 #[allow(dead_code)]
281 pub(crate) unsafe fn from_ffi_ptr<'_a>(from: *const $ty) -> &'_a Self {
282 std::mem::transmute(from)
283 }
284
285 #[allow(dead_code)]
286 pub(crate) fn from_ffi_ref(from: &$ty) -> &Self {
287 unsafe { std::mem::transmute(from) }
288 }
289
290 #[allow(dead_code)]
291 pub(crate) unsafe fn from_ffi_mut<'_a>(from: *mut $ty) -> Pin<&'_a mut Self> {
292 std::mem::transmute(from)
293 }
294
295 #[allow(dead_code)]
296 pub(crate) fn as_ffi(&self) -> &$ty {
297 unsafe { std::mem::transmute(self) }
298 }
299
300 #[allow(dead_code)]
301 pub(crate) fn as_ffi_mut(self: Pin<&mut Self>) -> Pin<&mut $ty> {
302 unsafe { std::mem::transmute(self) }
303 }
304
305 #[allow(dead_code)]
306 pub(crate) fn as_ffi_mut_ptr(self: Pin<&mut Self>) -> *mut $ty {
307 unsafe { std::mem::transmute(self) }
308 }
309
310 #[allow(dead_code)]
311 pub(crate) unsafe fn as_ffi_mut_ptr_unpinned(&mut self) -> *mut $ty {
312 std::mem::transmute(self)
313 }
314 };
315}
316
317pub(crate) use unsafe_ffi_conversions;