ext_php_rs/describe/
abi.rs

1//! ABI-stable standard library types.
2//!
3//! The description module is used by the `cargo-php` sub-command to retrieve
4//! information about the extension. As Rust does not have a stable ABI, it is
5//! not as simple as working in the Rust domain, as if the CLI and extension
6//! Rust versions do not match, it cannot be assumed that the types have the
7//! same memory layout.
8//!
9//! This module contains thin wrappers around standard library types used by the
10//! describe function to provide some sort of ABI-stability.
11//!
12//! As a general rule of thumb, no Rust type is ABI-stable. Strictly speaking,
13//! [`usize`] should not be in use, but rather `size_t` or a similar type,
14//! however these are currently unstable.
15
16use std::{fmt::Display, ops::Deref, vec::Vec as StdVec};
17
18/// An immutable, ABI-stable [`Vec`][std::vec::Vec].
19#[repr(C)]
20pub struct Vec<T> {
21    ptr: *mut T,
22    len: usize,
23}
24
25impl<T> Deref for Vec<T> {
26    type Target = [T];
27
28    fn deref(&self) -> &Self::Target {
29        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
30    }
31}
32
33impl<T> Drop for Vec<T> {
34    fn drop(&mut self) {
35        unsafe {
36            let _ = Box::from_raw(std::ptr::slice_from_raw_parts_mut(self.ptr, self.len));
37        };
38    }
39}
40
41impl<T> From<StdVec<T>> for Vec<T> {
42    fn from(vec: StdVec<T>) -> Self {
43        let vec = vec.into_boxed_slice();
44        let len = vec.len();
45        let ptr = Box::into_raw(vec) as *mut T;
46
47        Self { ptr, len }
48    }
49}
50
51/// An immutable, ABI-stable borrowed [`&'static str`][str].
52#[repr(C)]
53pub struct Str {
54    ptr: *const u8,
55    len: usize,
56}
57
58impl Str {
59    /// Returns the string as a string slice.
60    ///
61    /// The lifetime is `'static` and can outlive the [`Str`] object, as you can
62    /// only initialize a [`Str`] through a static reference.
63    pub fn str(&self) -> &'static str {
64        unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, self.len)) }
65    }
66}
67
68impl From<&'static str> for Str {
69    fn from(val: &'static str) -> Self {
70        let ptr = val.as_ptr();
71        let len = val.len();
72        Self { ptr, len }
73    }
74}
75
76impl AsRef<str> for Str {
77    fn as_ref(&self) -> &str {
78        self.str()
79    }
80}
81
82impl Display for Str {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        self.str().fmt(f)
85    }
86}
87
88/// An ABI-stable [`Option`][std::option::Option].
89#[repr(C, u8)]
90pub enum Option<T> {
91    Some(T),
92    None,
93}