Skip to main content

miden_protobuf/decode/
verify.rs

1use alloc::collections::{BTreeMap, BTreeSet};
2use alloc::format;
3use alloc::vec::Vec;
4use core::convert::Infallible;
5use core::error::Error;
6use core::fmt::Debug;
7
8use super::{MapField, OptionalField, RepeatedField};
9use crate::{ConversionError, ConversionResultExt, Verify, VerifyWith, unwrap_infallible};
10
11impl<S: Verify<Error = Infallible>> OptionalField<S> {
12    /// Verifies the present value without introducing a fallible result.
13    /// Only available when the element verifier is statically infallible.
14    pub fn verify_infallible(self) -> Option<S::Verified> {
15        self.map(|value| unwrap_infallible(value.verify()))
16    }
17}
18
19impl<S: Verify<Error = Infallible>> RepeatedField<S> {
20    /// Verifies each value without introducing a fallible result, preserving order and duplicates.
21    /// Only available when the element verifier is statically infallible.
22    ///
23    /// A fallible element verifier cannot use this method:
24    ///
25    /// ```compile_fail,E0599
26    /// use miden_protobuf::{RepeatedField, Verify};
27    /// struct Entry(u32);
28    /// impl Verify for Entry {
29    ///     type Verified = u8;
30    ///     type Error = core::num::TryFromIntError;
31    ///     fn verify(self) -> Result<u8, Self::Error> { self.0.try_into() }
32    /// }
33    /// RepeatedField::new("entries", vec![Entry(256)]).verify_infallible();
34    /// ```
35    pub fn verify_infallible(self) -> Vec<S::Verified> {
36        self.map(|value| unwrap_infallible(value.verify()))
37    }
38}
39
40impl<K: Ord, S: Verify<Error = Infallible>> MapField<BTreeMap<K, S>> {
41    /// Verifies each value without introducing a fallible result, preserving keys.
42    /// Only available when the element verifier is statically infallible.
43    pub fn verify_infallible(self) -> BTreeMap<K, S::Verified> {
44        self.map(|value| unwrap_infallible(value.verify()))
45    }
46}
47
48#[cfg(feature = "std")]
49impl<K: Eq + core::hash::Hash, S: Verify<Error = Infallible>>
50    MapField<std::collections::HashMap<K, S>>
51{
52    /// Verifies each value without introducing a fallible result, preserving keys.
53    /// Only available when the element verifier is statically infallible.
54    pub fn verify_infallible(self) -> std::collections::HashMap<K, S::Verified> {
55        self.map(|value| unwrap_infallible(value.verify()))
56    }
57}
58
59impl<S: Verify> Verify for OptionalField<S> {
60    type Verified = Option<S::Verified>;
61    type Error = ConversionError;
62
63    fn verify(self) -> Result<Self::Verified, Self::Error> {
64        self.try_map(Verify::verify)
65    }
66}
67
68impl<S: VerifyWith<C>, C> VerifyWith<C> for OptionalField<S> {
69    type Verified = Option<S::Verified>;
70    type Error = ConversionError;
71
72    fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
73        self.try_map(|value| value.verify_with(context))
74    }
75}
76
77impl<S: Verify> Verify for RepeatedField<S> {
78    type Verified = Vec<S::Verified>;
79    type Error = ConversionError;
80
81    fn verify(self) -> Result<Self::Verified, Self::Error> {
82        self.try_map(Verify::verify)
83    }
84}
85
86impl<S: VerifyWith<C>, C: Clone> VerifyWith<C> for RepeatedField<S> {
87    type Verified = Vec<S::Verified>;
88    type Error = ConversionError;
89
90    fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
91        self.try_map(|value| value.verify_with(context.clone()))
92    }
93}
94
95impl<K: Ord + Debug, S: Verify> Verify for MapField<BTreeMap<K, S>> {
96    type Verified = BTreeMap<K, S::Verified>;
97    type Error = ConversionError;
98
99    fn verify(self) -> Result<Self::Verified, Self::Error> {
100        self.try_map(Verify::verify)
101    }
102}
103
104impl<K: Ord + Debug, S: VerifyWith<C>, C: Clone> VerifyWith<C> for MapField<BTreeMap<K, S>> {
105    type Verified = BTreeMap<K, S::Verified>;
106    type Error = ConversionError;
107
108    fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
109        self.try_map(|value| value.verify_with(context.clone()))
110    }
111}
112
113#[cfg(feature = "std")]
114impl<K: Eq + core::hash::Hash + Debug, S: Verify> Verify
115    for MapField<std::collections::HashMap<K, S>>
116{
117    type Verified = std::collections::HashMap<K, S::Verified>;
118    type Error = ConversionError;
119
120    fn verify(self) -> Result<Self::Verified, Self::Error> {
121        self.try_map(Verify::verify)
122    }
123}
124
125#[cfg(feature = "std")]
126impl<K: Eq + core::hash::Hash + Debug, S: VerifyWith<C>, C: Clone> VerifyWith<C>
127    for MapField<std::collections::HashMap<K, S>>
128{
129    type Verified = std::collections::HashMap<K, S::Verified>;
130    type Error = ConversionError;
131
132    fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
133        self.try_map(|value| value.verify_with(context.clone()))
134    }
135}
136
137/// How to handle equal verified values when converting a repeated field to a set.
138///
139/// There is no default policy. Equality is determined by the output set's `Ord` or `Eq`/`Hash`
140/// implementation, after each input has been verified.
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142pub enum DuplicatePolicy {
143    /// Fail at the first duplicate, attaching its input index to the field path.
144    Reject,
145    /// Keep the first verified value. Later equal values are still verified before discarding.
146    KeepFirst,
147}
148
149impl<S> RepeatedField<S> {
150    /// Verifies values in input order and collects them into a set using an explicit policy.
151    ///
152    /// Verification failures and rejected duplicates include the field name and input index.
153    /// Processing stops immediately on either error. This checks individual values and the
154    /// duplicate policy; other collection invariants belong to the containing verifier.
155    ///
156    /// ```
157    /// use miden_protobuf::{DuplicatePolicy, RepeatedField, Verify};
158    /// # use std::collections::BTreeSet;
159    /// # struct Entry(u32);
160    /// # impl Verify for Entry {
161    /// #     type Verified = u8;
162    /// #     type Error = core::num::TryFromIntError;
163    /// #     fn verify(self) -> Result<u8, Self::Error> { self.0.try_into() }
164    /// # }
165    /// let values = vec![Entry(1), Entry(2), Entry(1)];
166    /// let unique =
167    ///     RepeatedField::new("entries", values).verify_into_btree_set(DuplicatePolicy::KeepFirst)?;
168    /// # assert_eq!(unique, BTreeSet::from([1, 2]));
169    /// # Ok::<_, miden_protobuf::ConversionError>(())
170    /// ```
171    pub fn verify_into_btree_set(
172        self,
173        duplicates: DuplicatePolicy,
174    ) -> Result<BTreeSet<S::Verified>, ConversionError>
175    where
176        S: Verify,
177        S::Verified: Ord,
178    {
179        let mut values = BTreeSet::new();
180        self.verify_set(duplicates, Verify::verify, |value| values.insert(value))?;
181        Ok(values)
182    }
183
184    /// Contextual version of [`Self::verify_into_btree_set`]. Context is cloned per element;
185    /// pass `&context` to share it without cloning its contents.
186    pub fn verify_into_btree_set_with<C>(
187        self,
188        context: C,
189        duplicates: DuplicatePolicy,
190    ) -> Result<BTreeSet<S::Verified>, ConversionError>
191    where
192        S: VerifyWith<C>,
193        S::Verified: Ord,
194        C: Clone,
195    {
196        let mut values = BTreeSet::new();
197        self.verify_set(
198            duplicates,
199            |value| value.verify_with(context.clone()),
200            |value| values.insert(value),
201        )?;
202        Ok(values)
203    }
204
205    /// Verifies values in input order and collects them into a hash set.
206    ///
207    /// Has the same verification and duplicate semantics as [`Self::verify_into_btree_set`].
208    #[cfg(feature = "std")]
209    pub fn verify_into_hash_set(
210        self,
211        duplicates: DuplicatePolicy,
212    ) -> Result<std::collections::HashSet<S::Verified>, ConversionError>
213    where
214        S: Verify,
215        S::Verified: Eq + core::hash::Hash,
216    {
217        let mut values = std::collections::HashSet::new();
218        self.verify_set(duplicates, Verify::verify, |value| values.insert(value))?;
219        Ok(values)
220    }
221
222    /// Contextual version of [`Self::verify_into_hash_set`]. Context is cloned per element;
223    /// pass `&context` to share it without cloning its contents.
224    #[cfg(feature = "std")]
225    pub fn verify_into_hash_set_with<C>(
226        self,
227        context: C,
228        duplicates: DuplicatePolicy,
229    ) -> Result<std::collections::HashSet<S::Verified>, ConversionError>
230    where
231        S: VerifyWith<C>,
232        S::Verified: Eq + core::hash::Hash,
233        C: Clone,
234    {
235        let mut values = std::collections::HashSet::new();
236        self.verify_set(
237            duplicates,
238            |value| value.verify_with(context.clone()),
239            |value| values.insert(value),
240        )?;
241        Ok(values)
242    }
243
244    fn verify_set<T, E: Error + Send + Sync + 'static>(
245        self,
246        duplicates: DuplicatePolicy,
247        mut verify: impl FnMut(S) -> Result<T, E>,
248        mut insert: impl FnMut(T) -> bool,
249    ) -> Result<(), ConversionError> {
250        for (index, value) in self.values.into_iter().enumerate() {
251            let value = verify(value).with_context(|| format!("{}[{index}]", self.name))?;
252            if !insert(value) && duplicates == DuplicatePolicy::Reject {
253                return Err(ConversionError::message("duplicate verified value")
254                    .context(format!("{}[{index}]", self.name)));
255            }
256        }
257        Ok(())
258    }
259}