#![allow(clippy::exhaustive_structs)]
use serde::{Serialize, Serializer, ser::SerializeMap};
use super::{RetainKey, RetainedKeys, retained_event_keys};
use crate::{CanonicalJsonObject, CanonicalJsonValue, room_version_rules::RedactionRules};
#[derive(Debug, Clone, Copy, Default)]
pub struct RedactingSerializer<'a> {
rules: Option<&'a RedactionRules>,
custom_redacted_root_fields: &'a [&'a str],
}
impl<'a> RedactingSerializer<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn rules(mut self, rules: &'a RedactionRules) -> Self {
self.rules = Some(rules);
self
}
pub fn custom_redacted_root_fields(mut self, fields: &'a [&'a str]) -> Self {
self.custom_redacted_root_fields = fields;
self
}
pub fn serialize(&self, object: &CanonicalJsonObject) -> Result<String, serde_json::Error> {
let retained_keys = self
.rules
.map(|rules| {
retained_event_keys(object)
.map(|retained_keys| RetainedKeysWithRules { retained_keys, rules })
})
.transpose()
.map_err(serde::ser::Error::custom)?;
serde_json::to_string(&RedactingObjectSerializer {
object,
retained_keys,
custom_redacted_fields: self.custom_redacted_root_fields,
})
}
}
struct RedactingObjectSerializer<'a> {
object: &'a CanonicalJsonObject,
retained_keys: Option<RetainedKeysWithRules<'a>>,
custom_redacted_fields: &'a [&'a str],
}
impl<'a> Serialize for RedactingObjectSerializer<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut serialize_map = serializer.serialize_map(None)?;
for (key, value) in self.object {
if self.custom_redacted_fields.contains(&key.as_str()) {
continue;
}
if let Some(RetainedKeysWithRules { retained_keys, rules }) = &self.retained_keys {
if let RetainKey::Yes { child_retained_keys } =
retained_keys.should_retain_key(rules, key)
{
if let Some(retained_keys) = child_retained_keys
&& let CanonicalJsonValue::Object(child_object) = value
{
serialize_map.serialize_entry(
key,
&Self {
object: child_object,
retained_keys: Some(RetainedKeysWithRules { retained_keys, rules }),
custom_redacted_fields: &[],
},
)?;
} else {
serialize_map.serialize_entry(key, value)?;
}
}
} else {
serialize_map.serialize_entry(key, value)?;
}
}
serialize_map.end()
}
}
struct RetainedKeysWithRules<'a> {
retained_keys: RetainedKeys,
rules: &'a RedactionRules,
}