Skip to main content

qubit_redact/domain/internal/
redact_value_serialize.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Generated structured serialization capability and containers.
9
10use std::rc::Rc;
11use std::sync::Arc;
12
13use serde::Serializer;
14use serde::ser::SerializeSeq;
15use serde::ser::SerializeTuple;
16
17use super::redact_serialize::RedactSerialize;
18use super::redact_serialize_scope::admit_collection_items;
19use super::redact_serialize_scope::serialize_structured;
20use super::redacted_serialize_ref::RedactedSerializeRef;
21
22impl<T: RedactSerialize> RedactSerialize for Option<T> {
23    /// Serializes contained redacted values through the active policy scope.
24    ///
25    /// # Errors
26    ///
27    /// Propagates child serialization and shared-budget failures.
28    fn serialize_redacted<S>(&self, serializer: S, policy: &crate::RedactionPolicy) -> Result<S::Ok, S::Error>
29    where
30        S: Serializer,
31    {
32        match self {
33            Some(value) => value.serialize_redacted(serializer, policy),
34            None => serializer.serialize_none(),
35        }
36    }
37}
38
39impl<T: RedactSerialize> RedactSerialize for Vec<T> {
40    /// Serializes contained redacted values through the active policy scope.
41    ///
42    /// # Errors
43    ///
44    /// Propagates child serialization and shared-budget failures.
45    fn serialize_redacted<S>(&self, serializer: S, policy: &crate::RedactionPolicy) -> Result<S::Ok, S::Error>
46    where
47        S: Serializer,
48    {
49        serialize_structured(serializer, policy, |serializer| {
50            if !admit_collection_items(self.len()) {
51                return super::redact_serialize_scope::serialize_payload(
52                    serializer,
53                    policy.masking().mask_opaque(crate::Sensitivity::Secret),
54                );
55            }
56            let mut sequence = serializer.serialize_seq(Some(self.len()))?;
57            for value in self {
58                sequence.serialize_element(&RedactedSerializeRef::new(value, policy))?;
59            }
60            sequence.end()
61        })
62    }
63}
64
65impl<T: RedactSerialize, const N: usize> RedactSerialize for [T; N] {
66    /// Serializes contained redacted values through the active policy scope.
67    ///
68    /// # Errors
69    ///
70    /// Propagates child serialization and shared-budget failures.
71    fn serialize_redacted<S>(&self, serializer: S, policy: &crate::RedactionPolicy) -> Result<S::Ok, S::Error>
72    where
73        S: Serializer,
74    {
75        serialize_structured(serializer, policy, |serializer| {
76            if !admit_collection_items(N) {
77                return super::redact_serialize_scope::serialize_payload(
78                    serializer,
79                    policy.masking().mask_opaque(crate::Sensitivity::Secret),
80                );
81            }
82            let mut sequence = serializer.serialize_seq(Some(N))?;
83            for value in self {
84                sequence.serialize_element(&RedactedSerializeRef::new(value, policy))?;
85            }
86            sequence.end()
87        })
88    }
89}
90
91/// Generates tuple projections that prepay their arity before visiting
92/// children.
93macro_rules! tuple_redact_serialize {
94    ($count:expr; $($name:ident => $index:tt),+) => {
95        impl<$($name: RedactSerialize),+> RedactSerialize for ($($name,)+) {
96            /// Serializes contained redacted values through the active policy scope.
97            ///
98            /// # Errors
99            ///
100            /// Propagates child serialization and shared-budget failures.
101            fn serialize_redacted<S>(&self, serializer: S, policy: &crate::RedactionPolicy) -> Result<S::Ok, S::Error>
102            where
103                S: Serializer,
104            {
105                serialize_structured(serializer, policy, |serializer| {
106                if !admit_collection_items($count) {
107                    return super::redact_serialize_scope::serialize_payload(serializer,
108                        policy
109                            .masking()
110                            .mask_opaque(crate::Sensitivity::Secret)
111                            .as_ref(),
112                    );
113                }
114                let mut tuple = serializer.serialize_tuple($count)?;
115                $(tuple.serialize_element(&RedactedSerializeRef::new(&self.$index, policy))?;)+
116                tuple.end()
117                })
118            }
119        }
120    };
121}
122
123tuple_redact_serialize!(1; A => 0);
124tuple_redact_serialize!(2; A => 0, B => 1);
125tuple_redact_serialize!(3; A => 0, B => 1, C => 2);
126tuple_redact_serialize!(4; A => 0, B => 1, C => 2, D => 3);
127tuple_redact_serialize!(5; A => 0, B => 1, C => 2, D => 3, E => 4);
128tuple_redact_serialize!(6; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5);
129tuple_redact_serialize!(7; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6);
130tuple_redact_serialize!(8; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7);
131tuple_redact_serialize!(9; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8);
132tuple_redact_serialize!(10; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9);
133tuple_redact_serialize!(11; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9, K => 10);
134tuple_redact_serialize!(12; A => 0, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7, I => 8, J => 9, K => 10, L => 11);
135
136/// Forwards a borrowed smart-pointer pointee without introducing a serializer
137/// wrapper type at each recursive model edge.
138macro_rules! pointer_redact_serialize {
139    ($pointer:ident) => {
140        impl<T: RedactSerialize + ?Sized> RedactSerialize for $pointer<T> {
141            /// Preserves the active policy and destination serializer.
142            fn serialize_redacted<S: Serializer>(
143                &self,
144                serializer: S,
145                policy: &crate::RedactionPolicy,
146            ) -> Result<S::Ok, S::Error> {
147                (**self).serialize_redacted(serializer, policy)
148            }
149        }
150    };
151}
152
153pointer_redact_serialize!(Box);
154pointer_redact_serialize!(Rc);
155pointer_redact_serialize!(Arc);