use std::fmt;
pub(in crate::policy) struct BoundedMaskWriter {
output: String,
max_bytes: usize,
truncated: bool,
}
impl BoundedMaskWriter {
#[must_use]
#[inline(always)]
pub(in crate::policy) fn new(max_bytes: usize) -> Self {
Self {
output: String::new(),
max_bytes,
truncated: false,
}
}
#[inline(always)]
pub(in crate::policy) fn finish(self) -> (String, bool) {
(self.output, self.truncated)
}
}
impl fmt::Write for BoundedMaskWriter {
fn write_str(&mut self, value: &str) -> fmt::Result {
let remaining = self.max_bytes.saturating_sub(self.output.len());
let mut end = value.len().min(remaining);
while !value.is_char_boundary(end) {
end -= 1;
}
self.output.push_str(&value[..end]);
self.truncated |= end < value.len();
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::fmt::Write;
use super::BoundedMaskWriter;
#[test]
fn test_writer_keeps_only_complete_utf8_prefixes_across_writes() {
let mut writer = BoundedMaskWriter::new(5);
writer.write_str("甲乙").expect("the bounded writer must never fail");
writer.write_str("z").expect("the bounded writer must never fail");
let (output, truncated) = writer.finish();
assert_eq!(output, "甲z");
assert!(truncated);
}
#[test]
fn test_writer_marks_empty_budget_as_truncated_for_non_empty_input() {
let mut writer = BoundedMaskWriter::new(0);
writer.write_str("mask").expect("the bounded writer must never fail");
let (output, truncated) = writer.finish();
assert_eq!(output, "");
assert!(truncated);
}
}