Skip to main content

ffi_types/
c.rs

1use crate::slice::SliceInner;
2
3pub const CXX_INCLUDE_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/include");
4pub const CXX_HEADER_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/include/rust_types.hxx");
5pub const CXX_HEADER_CONTENT: &str = include_str!("../include/rust_types.hxx");
6
7#[allow(non_camel_case_types)]
8#[cfg(feature = "libc")]
9type c_char = libc::c_char;
10#[allow(non_camel_case_types)]
11#[cfg(not(feature = "libc"))]
12type c_char = u8;
13
14pub type COptionBox<T> = crate::OptionBox<T>;
15pub type CBox<T> = COptionBox<T>;
16
17pub type CSliceRef<T> = crate::SliceRef<T>;
18pub type CBoxedSlice<T> = crate::BoxedSlice<T>;
19pub type CByteSliceRef = crate::ByteSliceRef;
20pub type CBoxedByteSlice = crate::BoxedByteSlice;
21
22pub type CStrRef = crate::StrRef;
23
24/// not related to [`std::ffi::CStr`] or [`std::ffi::CString`]
25pub type CharStrRef = crate::SliceRef<c_char>;
26
27impl From<crate::StrRef> for CharStrRef {
28    #[inline(always)]
29    fn from(s: crate::StrRef) -> Self {
30        Self(SliceInner {
31            ptr: s.0.ptr as *mut c_char,
32            len: s.0.len,
33        })
34    }
35}
36
37impl CharStrRef {
38    #[cfg(feature = "libc")]
39    #[inline(always)]
40    pub fn as_bytes(&self) -> &[u8] {
41        let len = self.len();
42        let ptr = self.as_ptr();
43        unsafe { core::slice::from_raw_parts(ptr as *const _, len) }
44    }
45    #[cfg(not(feature = "libc"))]
46    #[inline(always)]
47    fn as_bytes(&self) -> &[u8] {
48        self.as_ref()
49    }
50
51    #[inline(always)]
52    pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
53        core::str::from_utf8(self.as_bytes())
54    }
55
56    #[inline(always)]
57    pub fn unwrap_str(&self) -> &str {
58        self.to_str().unwrap()
59    }
60
61    #[inline(always)]
62    pub fn expect_str(&self, msg: &str) -> &str {
63        self.to_str().expect(msg)
64    }
65
66    /// # Safety
67    /// `self` must be a valid utf-8 string.
68    #[inline(always)]
69    pub unsafe fn into_rust_unchecked(self) -> crate::StrRef {
70        let inner = self.0;
71        crate::StrRef(SliceInner {
72            ptr: inner.ptr as *mut _,
73            len: inner.len,
74        })
75    }
76
77    #[inline(always)]
78    pub fn into_rust(self) -> Result<crate::StrRef, core::str::Utf8Error> {
79        core::str::from_utf8(self.as_bytes())?;
80        Ok(unsafe { self.into_rust_unchecked() })
81    }
82}
83
84pub type CBoxedStr = crate::BoxedStr;
85
86pub mod ffi {
87    use super::*;
88
89    #[unsafe(export_name = "_rust_ffi_boxed_str_drop")]
90    pub unsafe extern "C" fn boxed_str_drop(_string: CBoxedStr) {}
91
92    #[unsafe(export_name = "_rust_ffi_boxed_bytes_drop")]
93    pub unsafe extern "C" fn boxed_bytes_drop(_slice: CBoxedByteSlice) {}
94
95    /// Clone a BoxedStr by allocating a new copy.
96    #[unsafe(export_name = "_rust_ffi_boxed_str_clone")]
97    pub unsafe extern "C" fn boxed_str_clone(string: &CBoxedStr) -> CBoxedStr {
98        string.clone()
99    }
100
101    /// Clone a BoxedSlice<u8> by allocating a new copy.
102    #[unsafe(export_name = "_rust_ffi_boxed_bytes_clone")]
103    pub unsafe extern "C" fn boxed_bytes_clone(slice: &CBoxedByteSlice) -> CBoxedByteSlice {
104        slice.clone()
105    }
106}
107
108#[test]
109fn test_empty_str() {
110    // ensure dropping empty str is no-op
111    let empty = CBoxedStr::new("".into());
112    drop(empty);
113}
114
115#[test]
116fn test_empty_slice() {
117    // ensure dropping empty slice is no-op
118    let empty = CBoxedSlice::<u8>::empty();
119    drop(empty);
120}
121
122#[test]
123fn test_empty_char_str() {
124    // ensure dropping empty char str is no-op
125    let empty = CharStrRef::new(&[]);
126    let bytes = empty.as_bytes();
127    assert_eq!(bytes, b"");
128
129    let empty = CharStrRef {
130        0: SliceInner {
131            ptr: core::mem::align_of::<c_char>() as _,
132            len: 0,
133        },
134    };
135    let bytes = empty.as_bytes();
136    assert_eq!(bytes, b"");
137}
138
139#[test]
140fn test_empty_slice_alignment() {
141    // ensure empty slice dangling pointer respects alignment of T
142    let empty_u8 = CBoxedSlice::<u8>::empty();
143    assert_eq!(empty_u8.0.ptr as usize, core::mem::align_of::<u8>());
144    core::mem::forget(empty_u8);
145
146    let empty_u32 = CBoxedSlice::<u32>::empty();
147    assert_eq!(empty_u32.0.ptr as usize, core::mem::align_of::<u32>());
148    core::mem::forget(empty_u32);
149
150    let empty_u64 = CBoxedSlice::<u64>::empty();
151    assert_eq!(empty_u64.0.ptr as usize, core::mem::align_of::<u64>());
152    core::mem::forget(empty_u64);
153}