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
100
101
102
103
104
105
106
107
108
use std::ffi::{CStr, CString};
use std::{fmt, ops, ptr};

use crate::raw::root::RED4ext as red;

/// A dynamically allocated string.
#[repr(transparent)]
pub struct RedString(red::CString);

impl RedString {
    /// Creates a new empty string.
    #[inline]
    pub fn new() -> Self {
        Self(unsafe { red::CString::new(ptr::null_mut()) })
    }
}

impl Default for RedString {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl Clone for RedString {
    #[inline]
    fn clone(&self) -> Self {
        Self::from(self.as_ref())
    }
}

impl ops::Deref for RedString {
    type Target = CStr;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { CStr::from_ptr(self.0.c_str()) }
    }
}

impl From<&CStr> for RedString {
    #[inline]
    fn from(value: &CStr) -> Self {
        Self(unsafe { red::CString::new1(value.as_ptr(), ptr::null_mut()) })
    }
}

impl From<&str> for RedString {
    #[inline]
    fn from(value: &str) -> Self {
        Self(unsafe {
            red::CString::new2(
                value.as_ptr() as *const i8,
                value.len() as u32,
                ptr::null_mut(),
            )
        })
    }
}

impl From<CString> for RedString {
    #[inline]
    fn from(value: CString) -> Self {
        value.as_c_str().into()
    }
}

impl From<String> for RedString {
    #[inline]
    fn from(value: String) -> Self {
        RedString::from(crate::truncated_cstring(value))
    }
}

impl From<RedString> for String {
    #[inline]
    fn from(value: RedString) -> Self {
        value.to_string_lossy().into_owned()
    }
}

impl AsRef<CStr> for RedString {
    #[inline]
    fn as_ref(&self) -> &CStr {
        self
    }
}

impl fmt::Debug for RedString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self.as_ref())
    }
}

impl fmt::Display for RedString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.to_string_lossy())
    }
}

impl Drop for RedString {
    #[inline]
    fn drop(&mut self) {
        unsafe { self.0.destruct() }
    }
}