1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! The corresponding C and Swift code can be found in
//! crates/swift-bridge-build/src/generate_core/rust_string.{c.h,swift}
pub use self::ffi::*;

#[swift_bridge_macro::bridge(swift_bridge_path = crate)]
mod ffi {
    extern "Rust" {
        type RustString;

        #[swift_bridge(init)]
        fn new() -> RustString;

        #[swift_bridge(init)]
        fn new_with_str(str: &str) -> RustString;

        fn len(&self) -> usize;

        fn as_str(&self) -> &str;

        fn trim(&self) -> &str;
    }
}

#[doc(hidden)]
pub struct RustString(pub String);

#[doc(hidden)]
#[repr(C)]
pub struct RustStr {
    pub start: *const u8,
    pub len: usize,
}

impl RustString {
    fn new() -> Self {
        RustString("".to_string())
    }

    fn new_with_str(str: &str) -> Self {
        RustString(str.to_string())
    }

    fn len(&self) -> usize {
        self.0.len()
    }

    fn as_str(&self) -> &str {
        self.0.as_str()
    }

    fn trim(&self) -> &str {
        self.0.trim()
    }
}

impl RustString {
    /// Box::into_raw(Box::new(self))
    pub fn box_into_raw(self) -> *mut RustString {
        Box::into_raw(Box::new(self))
    }
}

impl RustStr {
    pub fn len(&self) -> usize {
        self.len
    }

    // TODO: Think through these lifetimes and the implications of them...
    pub fn to_str<'a>(self) -> &'a str {
        let bytes = unsafe { std::slice::from_raw_parts(self.start, self.len) };
        std::str::from_utf8(bytes).expect("Failed to convert RustStr to &str")
    }

    pub fn to_string(self) -> String {
        self.to_str().to_string()
    }

    pub fn from_str(str: &str) -> Self {
        RustStr {
            start: str.as_ptr(),
            len: str.len(),
        }
    }
}

impl PartialEq for RustStr {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            std::slice::from_raw_parts(self.start, self.len)
                == std::slice::from_raw_parts(other.start, other.len)
        }
    }
}

#[export_name = "__swift_bridge__$RustStr$partial_eq"]
#[allow(non_snake_case)]
pub extern "C" fn __swift_bridge__RustStr_partial_eq(lhs: RustStr, rhs: RustStr) -> bool {
    lhs == rhs
}