Skip to main content

neotron_ffi/
string.rs

1//! FFI-safe types used in the various Neotron APIs.
2//!
3//! Note that all types in this file that are exported in the `Api` structure
4//! *must* be `#[repr(C)]` and ABI stable.
5
6use crate::slice::FfiByteSlice;
7
8// ============================================================================
9// Imports
10// ============================================================================
11
12// None
13
14// ============================================================================
15// Constants
16// ============================================================================
17
18// None
19
20// ============================================================================
21// Types
22// ============================================================================
23
24/// A Rust UTF-8 string, but compatible with FFI.
25///
26/// Assume the lifetime is only valid until the callee returns to the caller. Is
27/// not null-terminated.
28#[repr(C)]
29#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
30pub struct FfiString<'a>(FfiByteSlice<'a>);
31
32impl<'a> FfiString<'a> {
33    /// Create a new string slice we can send over the FFI.
34    pub fn new(s: &'a str) -> FfiString<'a> {
35        FfiString(FfiByteSlice::new(s.as_bytes()))
36    }
37
38    /// Turn this FFI string into a Rust string slice.
39    pub fn as_str(&'a self) -> &'a str {
40        unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
41    }
42}
43
44impl<'a> From<&'a str> for FfiString<'a> {
45    /// Create a new FFI string from a string slice.
46    fn from(input: &'a str) -> FfiString<'a> {
47        FfiString::new(input)
48    }
49}
50
51impl core::fmt::Debug for FfiString<'_> {
52    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
53        let buffer = unsafe { core::slice::from_raw_parts(self.0.data, self.0.data_len) };
54        let s = unsafe { core::str::from_utf8_unchecked(buffer) };
55        write!(f, "{:?}", s)
56    }
57}
58
59impl core::fmt::Display for FfiString<'_> {
60    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
61        let buffer = unsafe { core::slice::from_raw_parts(self.0.data, self.0.data_len) };
62        let s = unsafe { core::str::from_utf8_unchecked(buffer) };
63        write!(f, "{}", s)
64    }
65}
66
67// ============================================================================
68// Tests
69// ============================================================================
70
71#[cfg(test)]
72mod test {
73    use super::*;
74
75    #[test]
76    fn make_string() {
77        let s: FfiString = "Hello, world!".into();
78        let output = s.to_string();
79        assert_eq!(&output, "Hello, world!");
80    }
81}
82
83// ============================================================================
84// End of File
85// ============================================================================