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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
use std::borrow::Borrow;
use std::ffi::CStr;
use std::fmt;
use std::ops::{Deref, Index, RangeFull};
use std::os::raw::c_char;
use std::str;

#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
pub struct ImString(Vec<u8>);

impl ImString {
    pub fn new<T: Into<String>>(value: T) -> ImString {
        unsafe { ImString::from_utf8_unchecked(value.into().into_bytes()) }
    }
    pub fn with_capacity(capacity: usize) -> ImString {
        let mut v = Vec::with_capacity(capacity + 1);
        v.push(b'\0');
        ImString(v)
    }
    pub unsafe fn from_utf8_unchecked(mut v: Vec<u8>) -> ImString {
        v.push(b'\0');
        ImString(v)
    }
    pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> ImString {
        ImString(v)
    }
    pub fn clear(&mut self) {
        self.0.clear();
        self.0.push(b'\0');
    }
    pub fn push(&mut self, ch: char) {
        let mut buf = [0; 4];
        self.push_str(ch.encode_utf8(&mut buf));
    }
    pub fn push_str(&mut self, string: &str) {
        self.refresh_len();
        self.0.extend_from_slice(string.as_bytes());
        self.0.push(b'\0');
    }
    pub fn capacity(&self) -> usize {
        self.0.capacity() - 1
    }
    pub fn capacity_with_nul(&self) -> usize {
        self.0.capacity()
    }
    pub fn reserve(&mut self, additional: usize) {
        self.0.reserve(additional);
    }
    pub fn reserve_exact(&mut self, additional: usize) {
        self.0.reserve_exact(additional);
    }
    pub fn as_ptr(&self) -> *const c_char {
        self.0.as_ptr() as *const _
    }
    pub fn as_mut_ptr(&mut self) -> *mut c_char {
        self.0.as_mut_ptr() as *mut _
    }

    /// Updates the buffer length based on the current contents.
    ///
    /// Dear imgui accesses pointers directly, so the length doesn't get updated when the contents
    /// change. This is normally OK, because Deref to ImStr always calculates the slice length
    /// based on contents. However, we need to refresh the length in some ImString functions.
    fn refresh_len(&mut self) {
        let len = self.to_str().len();
        unsafe {
            self.0.set_len(len);
        }
    }
}

impl<'a> Default for ImString {
    fn default() -> ImString {
        unsafe { ImString::from_utf8_with_nul_unchecked(vec![0]) }
    }
}

impl From<String> for ImString {
    fn from(s: String) -> ImString {
        ImString::new(s)
    }
}

impl<'a, T: ?Sized + AsRef<ImStr>> From<&'a T> for ImString {
    fn from(s: &'a T) -> ImString {
        s.as_ref().to_owned()
    }
}

impl AsRef<ImStr> for ImString {
    fn as_ref(&self) -> &ImStr {
        self
    }
}

impl Borrow<ImStr> for ImString {
    fn borrow(&self) -> &ImStr {
        self
    }
}

impl AsRef<str> for ImString {
    fn as_ref(&self) -> &str {
        self.to_str()
    }
}

impl Borrow<str> for ImString {
    fn borrow(&self) -> &str {
        self.to_str()
    }
}

impl Index<RangeFull> for ImString {
    type Output = ImStr;
    fn index(&self, _index: RangeFull) -> &ImStr {
        self
    }
}

impl fmt::Debug for ImString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self.to_str(), f)
    }
}

impl Deref for ImString {
    type Target = ImStr;
    fn deref(&self) -> &ImStr {
        // as_ptr() is used, because we need to look at the bytes to figure out the length
        // self.0.len() is incorrect, because there might be more than one nul byte in the end
        unsafe {
            &*(CStr::from_ptr(self.0.as_ptr() as *const c_char) as *const CStr as *const ImStr)
        }
    }
}

#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ImStr(CStr);

impl<'a> Default for &'a ImStr {
    fn default() -> &'a ImStr {
        static SLICE: &'static [u8] = &[0];
        unsafe { ImStr::from_utf8_with_nul_unchecked(SLICE) }
    }
}

impl fmt::Debug for ImStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl ImStr {
    pub fn new<S: AsRef<ImStr> + ?Sized>(s: &S) -> &ImStr {
        s.as_ref()
    }
    pub unsafe fn from_utf8_with_nul_unchecked(bytes: &[u8]) -> &ImStr {
        &*(bytes as *const [u8] as *const ImStr)
    }
    pub fn as_ptr(&self) -> *const c_char {
        self.0.as_ptr()
    }
    pub fn to_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.0.to_bytes()) }
    }
}

impl AsRef<CStr> for ImStr {
    fn as_ref(&self) -> &CStr {
        &self.0
    }
}

impl AsRef<ImStr> for ImStr {
    fn as_ref(&self) -> &ImStr {
        self
    }
}

impl AsRef<str> for ImStr {
    fn as_ref(&self) -> &str {
        self.to_str()
    }
}

impl ToOwned for ImStr {
    type Owned = ImString;
    fn to_owned(&self) -> ImString {
        ImString(self.0.to_owned().into_bytes())
    }
}