dear_imgui_rs/string/
im_string.rs1use std::fmt;
2use std::ops::{Deref, Index, RangeFull};
3use std::os::raw::c_char;
4use std::str;
5
6#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
8pub struct ImString(pub(crate) Vec<u8>);
9
10impl ImString {
11 pub fn new<T: Into<String>>(value: T) -> ImString {
13 let value = value.into();
14 assert!(!value.contains('\0'), "ImString contained null byte");
15 unsafe {
16 let mut s = ImString::from_utf8_unchecked(value.into_bytes());
17 s.refresh_len();
18 s
19 }
20 }
21
22 #[inline]
24 pub fn with_capacity(capacity: usize) -> ImString {
25 let mut v = Vec::with_capacity(capacity + 1);
26 v.push(b'\0');
27 ImString(v)
28 }
29
30 #[inline]
37 pub unsafe fn from_utf8_unchecked(mut v: Vec<u8>) -> ImString {
38 v.push(b'\0');
39 ImString(v)
40 }
41
42 #[inline]
49 pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> ImString {
50 ImString(v)
51 }
52
53 #[inline]
55 pub fn clear(&mut self) {
56 self.0.clear();
57 self.0.push(b'\0');
58 }
59
60 #[inline]
62 pub fn push(&mut self, ch: char) {
63 let mut buf = [0; 4];
64 self.push_str(ch.encode_utf8(&mut buf));
65 }
66
67 #[inline]
69 pub fn push_str(&mut self, string: &str) {
70 assert!(!string.contains('\0'), "ImString contained null byte");
71 self.0.pop();
72 self.0.extend(string.bytes());
73 self.0.push(b'\0');
74 unsafe {
75 self.refresh_len();
76 }
77 }
78
79 #[inline]
81 pub fn capacity(&self) -> usize {
82 self.0.capacity() - 1
83 }
84
85 #[inline]
87 pub fn capacity_with_nul(&self) -> usize {
88 self.0.capacity()
89 }
90
91 pub fn reserve(&mut self, additional: usize) {
96 self.0.reserve(additional);
97 }
98
99 pub fn reserve_exact(&mut self, additional: usize) {
102 self.0.reserve_exact(additional);
103 }
104
105 #[inline]
107 pub fn as_ptr(&self) -> *const c_char {
108 self.0.as_ptr() as *const c_char
109 }
110
111 #[inline]
115 pub fn as_mut_ptr(&mut self) -> *mut c_char {
116 self.0.as_mut_ptr() as *mut c_char
117 }
118
119 pub(crate) fn ensure_buf_size(&mut self, buf_size: usize) {
124 if self.0.len() < buf_size {
125 self.0.resize(buf_size, 0);
126 } else if self.0.len() > buf_size {
127 self.0.truncate(buf_size);
128 if let Some(last) = self.0.last_mut() {
129 *last = 0;
130 } else {
131 self.0.push(0);
132 }
133 } else if let Some(last) = self.0.last_mut() {
134 *last = 0;
135 }
136 }
137
138 pub unsafe fn refresh_len(&mut self) {
145 if let Some(pos) = self.0.iter().position(|&b| b == 0) {
146 self.0.truncate(pos + 1);
147 } else {
148 self.0.push(0);
149 }
150 }
151
152 pub fn len(&self) -> usize {
154 self.0.len().saturating_sub(1)
155 }
156
157 pub fn is_empty(&self) -> bool {
159 self.len() == 0
160 }
161
162 pub fn to_str(&self) -> &str {
164 unsafe { str::from_utf8_unchecked(&self.0[..self.len()]) }
165 }
166}
167
168impl Default for ImString {
169 fn default() -> Self {
170 ImString::with_capacity(0)
171 }
172}
173
174impl fmt::Display for ImString {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 fmt::Display::fmt(self.to_str(), f)
177 }
178}
179
180impl fmt::Debug for ImString {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 fmt::Debug::fmt(self.to_str(), f)
183 }
184}
185
186impl Deref for ImString {
187 type Target = str;
188 fn deref(&self) -> &str {
189 self.to_str()
190 }
191}
192
193impl AsRef<str> for ImString {
194 fn as_ref(&self) -> &str {
195 self.to_str()
196 }
197}
198
199impl From<String> for ImString {
200 fn from(s: String) -> ImString {
201 ImString::new(s)
202 }
203}
204
205impl From<&str> for ImString {
206 fn from(s: &str) -> ImString {
207 ImString::new(s)
208 }
209}
210
211impl Index<RangeFull> for ImString {
212 type Output = str;
213 fn index(&self, _index: RangeFull) -> &str {
214 self.to_str()
215 }
216}