use std::os::raw::c_char;
#[derive(Debug)]
pub struct UiBuffer {
pub buffer: Vec<u8>,
pub max_len: usize,
}
impl UiBuffer {
pub const fn new(max_len: usize) -> Self {
Self {
buffer: Vec::new(),
max_len,
}
}
pub fn scratch_txt(&mut self, txt: impl AsRef<str>) -> *const c_char {
self.refresh_buffer();
let start_of_substr = self.push(txt);
unsafe { self.offset(start_of_substr) }
}
pub fn scratch_txt_opt(&mut self, txt: Option<impl AsRef<str>>) -> *const c_char {
match txt {
Some(v) => self.scratch_txt(v),
None => std::ptr::null(),
}
}
pub fn scratch_txt_two(
&mut self,
txt_0: impl AsRef<str>,
txt_1: impl AsRef<str>,
) -> (*const c_char, *const c_char) {
self.refresh_buffer();
let first_offset = self.push(txt_0);
let second_offset = self.push(txt_1);
unsafe { (self.offset(first_offset), self.offset(second_offset)) }
}
pub fn scratch_txt_with_opt(
&mut self,
txt_0: impl AsRef<str>,
txt_1: Option<impl AsRef<str>>,
) -> (*const c_char, *const c_char) {
match txt_1 {
Some(value) => self.scratch_txt_two(txt_0, value),
None => (self.scratch_txt(txt_0), std::ptr::null()),
}
}
pub fn refresh_buffer(&mut self) {
if self.buffer.len() > self.max_len {
self.buffer.clear();
}
}
pub unsafe fn offset(&self, pos: usize) -> *const c_char {
unsafe { self.buffer.as_ptr().add(pos) as *const _ }
}
pub fn push(&mut self, txt: impl AsRef<str>) -> usize {
let txt = txt.as_ref();
let len = self.buffer.len();
let bytes = txt.as_bytes();
if bytes.contains(&0) {
self.buffer
.extend(bytes.iter().map(|&b| if b == 0 { b'?' } else { b }));
} else {
self.buffer.extend(bytes);
}
self.buffer.push(b'\0');
len
}
}