1use std::borrow::Cow;
2use std::fmt;
3use std::ops::{Deref, Index, RangeFull};
4use std::os::raw::c_char;
5use std::str;
6
7#[derive(Debug)]
9pub struct UiBuffer {
10 pub buffer: Vec<u8>,
11 pub max_len: usize,
12}
13
14impl UiBuffer {
15 pub const fn new(max_len: usize) -> Self {
17 Self {
18 buffer: Vec::new(),
19 max_len,
20 }
21 }
22
23 pub fn scratch_txt(&mut self, txt: impl AsRef<str>) -> *const std::os::raw::c_char {
25 self.refresh_buffer();
26
27 let start_of_substr = self.push(txt);
28 unsafe { self.offset(start_of_substr) }
29 }
30
31 pub fn scratch_txt_opt(&mut self, txt: Option<impl AsRef<str>>) -> *const std::os::raw::c_char {
33 match txt {
34 Some(v) => self.scratch_txt(v),
35 None => std::ptr::null(),
36 }
37 }
38
39 pub fn scratch_txt_two(
41 &mut self,
42 txt_0: impl AsRef<str>,
43 txt_1: impl AsRef<str>,
44 ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
45 self.refresh_buffer();
46
47 let first_offset = self.push(txt_0);
48 let second_offset = self.push(txt_1);
49
50 unsafe { (self.offset(first_offset), self.offset(second_offset)) }
51 }
52
53 pub fn scratch_txt_with_opt(
55 &mut self,
56 txt_0: impl AsRef<str>,
57 txt_1: Option<impl AsRef<str>>,
58 ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
59 match txt_1 {
60 Some(value) => self.scratch_txt_two(txt_0, value),
61 None => (self.scratch_txt(txt_0), std::ptr::null()),
62 }
63 }
64
65 pub fn refresh_buffer(&mut self) {
68 if self.buffer.len() > self.max_len {
69 self.buffer.clear();
70 }
71 }
72
73 pub unsafe fn offset(&self, pos: usize) -> *const std::os::raw::c_char {
79 unsafe { self.buffer.as_ptr().add(pos) as *const _ }
80 }
81
82 pub fn push(&mut self, txt: impl AsRef<str>) -> usize {
85 let len = self.buffer.len();
86 self.buffer.extend(txt.as_ref().as_bytes());
87 self.buffer.push(b'\0');
88
89 len
90 }
91}
92
93#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
95pub struct ImString(pub(crate) Vec<u8>);
96
97impl ImString {
98 pub fn new<T: Into<String>>(value: T) -> ImString {
100 unsafe {
101 let mut s = ImString::from_utf8_unchecked(value.into().into_bytes());
102 s.refresh_len();
103 s
104 }
105 }
106
107 #[inline]
109 pub fn with_capacity(capacity: usize) -> ImString {
110 let mut v = Vec::with_capacity(capacity + 1);
111 v.push(b'\0');
112 ImString(v)
113 }
114
115 #[inline]
122 pub unsafe fn from_utf8_unchecked(mut v: Vec<u8>) -> ImString {
123 v.push(b'\0');
124 ImString(v)
125 }
126
127 #[inline]
134 pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> ImString {
135 ImString(v)
136 }
137
138 #[inline]
140 pub fn clear(&mut self) {
141 self.0.clear();
142 self.0.push(b'\0');
143 }
144
145 #[inline]
147 pub fn push(&mut self, ch: char) {
148 let mut buf = [0; 4];
149 self.push_str(ch.encode_utf8(&mut buf));
150 }
151
152 #[inline]
154 pub fn push_str(&mut self, string: &str) {
155 self.0.pop();
156 self.0.extend(string.bytes());
157 self.0.push(b'\0');
158 unsafe {
159 self.refresh_len();
160 }
161 }
162
163 #[inline]
165 pub fn capacity(&self) -> usize {
166 self.0.capacity() - 1
167 }
168
169 #[inline]
171 pub fn capacity_with_nul(&self) -> usize {
172 self.0.capacity()
173 }
174
175 pub fn reserve(&mut self, additional: usize) {
180 self.0.reserve(additional);
181 }
182
183 pub fn reserve_exact(&mut self, additional: usize) {
186 self.0.reserve_exact(additional);
187 }
188
189 #[inline]
191 pub fn as_ptr(&self) -> *const c_char {
192 self.0.as_ptr() as *const c_char
193 }
194
195 #[inline]
199 pub fn as_mut_ptr(&mut self) -> *mut c_char {
200 self.0.as_mut_ptr() as *mut c_char
201 }
202
203 pub unsafe fn refresh_len(&mut self) {
210 unsafe {
211 let mut len = 0;
214 let ptr = self.as_ptr() as *const u8;
215 while *ptr.add(len) != 0 {
216 len += 1;
217 }
218 self.0.set_len(len + 1);
219 }
220 }
221
222 pub fn len(&self) -> usize {
224 self.0.len().saturating_sub(1)
225 }
226
227 pub fn is_empty(&self) -> bool {
229 self.len() == 0
230 }
231
232 pub fn to_str(&self) -> &str {
234 unsafe { str::from_utf8_unchecked(&self.0[..self.len()]) }
235 }
236}
237
238impl Default for ImString {
239 fn default() -> Self {
240 ImString::with_capacity(0)
241 }
242}
243
244impl fmt::Display for ImString {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 fmt::Display::fmt(self.to_str(), f)
247 }
248}
249
250impl fmt::Debug for ImString {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 fmt::Debug::fmt(self.to_str(), f)
253 }
254}
255
256impl Deref for ImString {
257 type Target = str;
258 fn deref(&self) -> &str {
259 self.to_str()
260 }
261}
262
263impl AsRef<str> for ImString {
264 fn as_ref(&self) -> &str {
265 self.to_str()
266 }
267}
268
269impl From<String> for ImString {
270 fn from(s: String) -> ImString {
271 ImString::new(s)
272 }
273}
274
275impl From<&str> for ImString {
276 fn from(s: &str) -> ImString {
277 ImString::new(s)
278 }
279}
280
281impl Index<RangeFull> for ImString {
282 type Output = str;
283 fn index(&self, _index: RangeFull) -> &str {
284 self.to_str()
285 }
286}
287
288pub type ImStr<'a> = Cow<'a, str>;
290
291#[macro_export]
293macro_rules! im_str {
294 ($e:expr) => {{ $crate::ImString::new($e) }};
295}