use std::fmt::Debug;
use crate::Sensitivity;
use crate::domain::Redact;
use crate::domain::RedactLevelValue;
use crate::domain::RedactionWriter;
pub struct RedactionItems<'writer, 'session> {
pub(super) writer: &'writer mut RedactionWriter<'session>,
pub(super) admitted_item: bool,
}
impl<'writer, 'session> RedactionItems<'writer, 'session> {
pub fn for_each<I, F>(&mut self, values: I, mut write: F) -> &mut Self
where
I: IntoIterator,
F: FnMut(&mut Self, I::Item),
{
let mut values = values.into_iter();
while values.size_hint().1 != Some(0) {
if !self.writer.can_write() || !self.writer.session.preflight_collection_item() {
self.write_truncated();
break;
}
let Some(value) = values.next() else { break };
if !self.admit_item() {
self.write_truncated();
break;
}
self.admitted_item = true;
write(self, value);
self.admitted_item = false;
}
self
}
pub fn unredacted_item<T, F>(&mut self, access: F) -> &mut Self
where
T: Debug,
F: FnOnce() -> T,
{
if !self.admit_item() {
self.write_truncated();
return self;
}
if self.writer.session.is_inspection() {
return self;
}
self.writer.write_debug(&access());
self.writer.write_fragment(", ");
self
}
pub fn sensitive_item<T, F>(&mut self, level: Sensitivity, access: F) -> &mut Self
where
T: Debug,
F: FnOnce() -> T,
{
if self.writer.session.policy().is_disabled() {
return self.unredacted_item(access);
}
if !self.admit_item() {
self.write_truncated();
return self;
}
if self.writer.session.is_inspection() {
self.writer.session.observe_sensitivity(level);
return self;
}
if matches!(level, Sensitivity::High | Sensitivity::Secret) {
let value = self
.writer
.session
.policy()
.masking()
.mask_opaque_bounded(level, self.writer.remaining_output_bytes());
self.writer.write_debug(&value);
} else {
self.writer.write_masked_debug(level, &access());
}
self.writer.write_fragment(", ");
self
}
#[cfg(feature = "json")]
pub fn json_value_item(&mut self, value: &serde_json::Value) -> &mut Self {
if !self.admit_item() {
self.write_truncated();
return self;
}
self.writer.write_json_value(value);
self.writer.write_fragment(", ");
self
}
pub(crate) fn level_value<T>(&mut self, value: &T, level: Sensitivity) -> &mut Self
where
T: RedactLevelValue + ?Sized,
{
if !self.admit_item() {
self.write_truncated();
return self;
}
value.write_redacted_level(self.writer, level);
self.writer.write_fragment(", ");
self
}
pub fn nested_item<T>(&mut self, value: &T) -> &mut Self
where
T: Redact + ?Sized,
{
if !self.admit_item() {
self.write_truncated();
return self;
}
value.write_redacted(self.writer);
self.writer.write_fragment(", ");
self
}
fn admit_item(&mut self) -> bool {
if !self.writer.can_write() {
return false;
}
std::mem::take(&mut self.admitted_item) || self.writer.session.admit_domain_collection_item()
}
fn write_truncated(&mut self) {
if !self.writer.session.domain_frame_is_truncated() {
self.writer.write_fragment("<truncated>");
self.writer.truncate_without_output_limit();
}
}
}