use std::io;
use smallvec::SmallVec;
#[derive(Debug, Clone)]
pub(super) struct PrefixedStringBuf {
prefix_len: usize,
buf: String,
}
impl PrefixedStringBuf {
pub fn new(prefix: &str, capacity: usize) -> Self {
let prefix_len = prefix.len();
let mut buf = String::with_capacity(capacity);
buf.push_str(prefix);
Self { prefix_len, buf }
}
pub fn from_prefix(buf: String) -> Self {
Self {
prefix_len: buf.len(),
buf,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.buf.len() == self.prefix_len
}
pub fn clear(&mut self) {
self.buf.truncate(self.prefix_len);
self.buf.shrink_to(1024 * 1024);
}
#[inline]
pub fn push(&mut self, c: char) -> &mut Self {
self.buf.push(c);
self
}
#[inline]
pub fn push_raw_str<'a>(&'a mut self, s: &str) -> &'a mut Self {
self.buf.push_str(s);
self
}
#[inline]
pub fn push_integer(&mut self, s: impl itoa::Integer) -> &mut Self {
self.buf.push_str(itoa::Buffer::new().format(s));
self
}
#[inline]
pub fn extend_from_within_range(&mut self, start: usize, end: usize) -> &mut Self {
self.buf.extend_from_within(start..end);
self
}
pub fn as_str(&self) -> &str {
&self.buf
}
pub fn truncate(&mut self, combined_len: usize) {
assert!(combined_len >= self.prefix_len);
self.buf.truncate(combined_len);
}
}
impl crate::json_string::JsonString for PrefixedStringBuf {
fn json_string(&mut self, value: &str) -> &mut Self {
crate::json_string::JsonString::json_string(&mut self.buf, value);
self
}
}
impl AsRef<[u8]> for PrefixedStringBuf {
fn as_ref(&self) -> &[u8] {
self.buf.as_bytes()
}
}
pub(crate) fn write_all_vectored<V: AsRef<[u8]>, const N: usize>(
bufs: SmallVec<[V; N]>,
output: &mut impl io::Write,
) -> io::Result<()> {
debug_assert!(!bufs.is_empty() && bufs.len() <= N);
let mut slices: SmallVec<[_; N]> = bufs.iter().map(AsRef::as_ref).collect();
let mut slices = &mut slices[..];
let mut io_slices = SmallVec::<[io::IoSlice<'_>; N]>::new();
advance_slices(&mut slices, 0); while !slices.is_empty() {
io_slices.extend(slices.iter().map(|&s| io::IoSlice::new(s)));
match output.write_vectored(&io_slices) {
Ok(0) => return Err(io::ErrorKind::WriteZero.into()),
Ok(n) => advance_slices(&mut slices, n),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
io_slices.clear();
}
Ok(())
}
fn advance_slices(slices: &mut &mut [&[u8]], count: usize) {
let mut remaining = count;
while let Some(first) = slices.first_mut() {
if let Some(remainder) = remaining.checked_sub(first.len()) {
*slices = &mut std::mem::take(slices)[1..];
remaining = remainder;
} else {
*first = &first[remaining..];
return;
}
}
assert_eq!(remaining, 0);
}
#[cfg(test)]
mod test {
use super::PrefixedStringBuf;
#[test]
fn test_extend_from_within() {
let mut buf = PrefixedStringBuf::from_prefix("0123".into());
buf.push_raw_str("4567")
.extend_from_within_range(0, 2)
.extend_from_within_range(2, 8)
.extend_from_within_range(0, 0);
assert_eq!(buf.as_str(), "0123456701234567");
}
#[test]
fn test_truncate() {
let mut buf = PrefixedStringBuf::from_prefix("0123".into());
buf.push_raw_str("4567").truncate(4);
assert_eq!(buf.as_str(), "0123");
buf.push_raw_str("89ab").truncate(5);
assert_eq!(buf.as_str(), "01238");
}
}