ext_php_rs_introspection/
abi.rs1use std::{fmt::Display, ops::Deref, vec::Vec as StdVec};
17
18#[repr(C)]
20#[derive(Debug)]
21pub struct Vec<T> {
22 ptr: *mut T,
23 len: usize,
24}
25
26impl<T> Deref for Vec<T> {
27 type Target = [T];
28
29 fn deref(&self) -> &Self::Target {
30 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
31 }
32}
33
34impl<T> Drop for Vec<T> {
35 fn drop(&mut self) {
36 unsafe {
37 let _ = Box::from_raw(std::ptr::slice_from_raw_parts_mut(self.ptr, self.len));
38 };
39 }
40}
41
42impl<T> From<StdVec<T>> for Vec<T> {
43 fn from(vec: StdVec<T>) -> Self {
44 let vec = vec.into_boxed_slice();
45 let len = vec.len();
46 let ptr = Box::into_raw(vec).cast::<T>();
47
48 Self { ptr, len }
49 }
50}
51
52impl<T> PartialEq for Vec<T>
53where
54 T: PartialEq,
55{
56 fn eq(&self, other: &Self) -> bool {
57 self.len == other.len && self.as_ref() == other.as_ref()
58 }
59}
60
61#[repr(C)]
63#[derive(Debug, Clone, Copy)]
64pub struct Str {
65 ptr: *const u8,
66 len: usize,
67}
68
69impl Str {
70 #[must_use]
72 pub const fn new(val: &'static str) -> Self {
73 Self {
74 ptr: val.as_ptr(),
75 len: val.len(),
76 }
77 }
78
79 #[must_use]
84 pub const fn str(&self) -> &'static str {
85 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, self.len)) }
86 }
87}
88
89impl From<&'static str> for Str {
90 fn from(val: &'static str) -> Self {
91 Self::new(val)
92 }
93}
94
95impl AsRef<str> for Str {
96 fn as_ref(&self) -> &str {
97 self.str()
98 }
99}
100
101impl Display for Str {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 self.str().fmt(f)
104 }
105}
106
107impl PartialEq for Str {
108 fn eq(&self, other: &Self) -> bool {
109 self.len == other.len && self.str() == other.str()
110 }
111}
112
113impl Eq for Str {}
114
115unsafe impl Send for Str {}
117unsafe impl Sync for Str {}
119
120#[repr(C)]
122#[derive(Debug, PartialEq)]
123pub struct RString {
124 inner: Vec<u8>,
125}
126
127impl RString {
128 #[inline]
134 #[must_use]
135 pub fn as_str(&self) -> &str {
136 std::str::from_utf8(&self.inner).expect("RString value is not valid UTF-8")
137 }
138}
139
140impl From<&str> for RString {
141 fn from(s: &str) -> Self {
142 Self {
143 inner: s.as_bytes().to_vec().into(),
144 }
145 }
146}
147
148impl From<String> for RString {
149 fn from(s: String) -> Self {
150 Self {
151 inner: s.into_bytes().into(),
152 }
153 }
154}
155
156impl AsRef<str> for RString {
157 fn as_ref(&self) -> &str {
158 self.as_str()
159 }
160}
161
162impl Display for RString {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 self.as_str().fmt(f)
165 }
166}
167
168#[repr(C, u8)]
170#[derive(Debug, Clone, Copy)]
171pub enum Option<T> {
172 Some(T),
174 None,
176}
177
178impl<T> From<std::option::Option<T>> for Option<T> {
179 fn from(opt: std::option::Option<T>) -> Self {
180 match opt {
181 Some(val) => Self::Some(val),
182 None => Self::None,
183 }
184 }
185}
186
187impl<T> PartialEq for Option<T>
188where
189 T: PartialEq,
190{
191 fn eq(&self, other: &Self) -> bool {
192 match (self, other) {
193 (Self::Some(a), Self::Some(b)) => a == b,
194 (Self::None, Self::None) => true,
195 _ => false,
196 }
197 }
198}
199
200impl<T> Eq for Option<T> where T: Eq {}
201
202macro_rules! assert_ffi_safe {
207 ($t:ty, size = $size:literal, align = $align:literal) => {
208 const _: () = {
209 #[deny(improper_ctypes_definitions)]
210 #[allow(dead_code)]
211 extern "C" fn by_value(_: $t) {}
212 #[cfg(target_pointer_width = "64")]
213 assert!(::std::mem::size_of::<$t>() == $size && ::std::mem::align_of::<$t>() == $align);
214 };
215 };
216}
217pub(crate) use assert_ffi_safe;
218
219assert_ffi_safe!(Vec<u8>, size = 16, align = 8);
220assert_ffi_safe!(Str, size = 16, align = 8);
221assert_ffi_safe!(RString, size = 16, align = 8);
222assert_ffi_safe!(Option<Str>, size = 24, align = 8);