ruma_common/canonical_json/redaction/
serializer.rs1#![allow(clippy::exhaustive_structs)]
2
3use serde::{Serialize, Serializer, ser::SerializeMap};
4
5use super::{RetainKey, RetainedKeys, retained_event_keys};
6use crate::{CanonicalJsonObject, CanonicalJsonValue, room_version_rules::RedactionRules};
7
8#[derive(Debug, Clone, Copy, Default)]
17pub struct RedactingSerializer<'a> {
18 rules: Option<&'a RedactionRules>,
20
21 custom_redacted_root_fields: &'a [&'a str],
23}
24
25impl<'a> RedactingSerializer<'a> {
26 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn rules(mut self, rules: &'a RedactionRules) -> Self {
35 self.rules = Some(rules);
36 self
37 }
38
39 pub fn custom_redacted_root_fields(mut self, fields: &'a [&'a str]) -> Self {
41 self.custom_redacted_root_fields = fields;
42 self
43 }
44
45 pub fn serialize(&self, object: &CanonicalJsonObject) -> Result<String, serde_json::Error> {
47 let retained_keys = self
48 .rules
49 .map(|rules| {
50 retained_event_keys(object)
51 .map(|retained_keys| RetainedKeysWithRules { retained_keys, rules })
52 })
53 .transpose()
54 .map_err(serde::ser::Error::custom)?;
55
56 serde_json::to_string(&RedactingObjectSerializer {
57 object,
58 retained_keys,
59 custom_redacted_fields: self.custom_redacted_root_fields,
60 })
61 }
62}
63
64struct RedactingObjectSerializer<'a> {
66 object: &'a CanonicalJsonObject,
67 retained_keys: Option<RetainedKeysWithRules<'a>>,
68 custom_redacted_fields: &'a [&'a str],
69}
70
71impl<'a> Serialize for RedactingObjectSerializer<'a> {
72 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73 where
74 S: Serializer,
75 {
76 let mut serialize_map = serializer.serialize_map(None)?;
77
78 for (key, value) in self.object {
79 if self.custom_redacted_fields.contains(&key.as_str()) {
80 continue;
81 }
82
83 if let Some(RetainedKeysWithRules { retained_keys, rules }) = &self.retained_keys {
84 if let RetainKey::Yes { child_retained_keys } =
85 retained_keys.should_retain_key(rules, key)
86 {
87 if let Some(retained_keys) = child_retained_keys
89 && let CanonicalJsonValue::Object(child_object) = value
90 {
91 serialize_map.serialize_entry(
92 key,
93 &Self {
94 object: child_object,
95 retained_keys: Some(RetainedKeysWithRules { retained_keys, rules }),
96 custom_redacted_fields: &[],
97 },
98 )?;
99 } else {
100 serialize_map.serialize_entry(key, value)?;
101 }
102 }
103 } else {
104 serialize_map.serialize_entry(key, value)?;
105 }
106 }
107
108 serialize_map.end()
109 }
110}
111
112struct RetainedKeysWithRules<'a> {
114 retained_keys: RetainedKeys,
116
117 rules: &'a RedactionRules,
119}