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