bc_envelope/base/
queries.rs

1//! Provides methods for querying envelope structure and extracting data.
2//!
3//! The `queries` module contains methods for:
4//!
5//! 1. **Structural queries**: Methods for examining the envelope's structure
6//!    (`subject()`, `assertions()`)
7//! 2. **Type queries**: Methods for determining the envelope's type
8//!    (`is_leaf()`, `is_node()`, etc.)
9//! 3. **Content extraction**: Methods for extracting typed content from
10//!    envelopes (`extract_subject()`, `extract_object_for_predicate()`)
11//! 4. **Assertion queries**: Methods for finding assertions with specific
12//!    predicates (`assertion_with_predicate()`)
13//!
14//! These methods enable traversal and inspection of envelope hierarchies,
15//! allowing for flexible manipulation and access to envelope data structures.
16//!
17//! # Examples
18//!
19//! ```
20//! use bc_envelope::prelude::*;
21//!
22//! // Create an envelope with assertions
23//! let envelope = Envelope::new("Alice")
24//!     .add_assertion("name", "Alice Adams")
25//!     .add_assertion("age", 30)
26//!     .add_assertion("email", "alice@example.com");
27//!
28//! // Query the envelope structure
29//! let subject = envelope.subject(); // Returns "Alice"
30//! let assertions = envelope.assertions(); // Returns all assertions
31//!
32//! // Find assertions with a specific predicate
33//! if let Ok(email_assertion) = envelope.assertion_with_predicate("email") {
34//!     let email = email_assertion.as_object().unwrap();
35//!     assert_eq!(email.extract_subject::<String>().unwrap(), "alice@example.com");
36//! }
37//!
38//! // Extract typed data directly from the envelope
39//! let name = envelope.extract_object_for_predicate::<String>("name").unwrap();
40//! let age = envelope.extract_object_for_predicate::<i32>("age").unwrap();
41//!
42//! assert_eq!(name, "Alice Adams");
43//! assert_eq!(age, 30);
44//! ```
45
46use anyhow::{ bail, Result };
47use bc_components::{ Digest, DigestProvider };
48#[cfg(feature = "encrypt")]
49use bc_components::EncryptedMessage;
50#[cfg(feature = "compress")]
51use bc_components::Compressed;
52use dcbor::prelude::*;
53use std::any::{ Any, TypeId };
54
55use crate::{ Assertion, Envelope, EnvelopeEncodable, Error };
56#[cfg(feature = "known_value")]
57use crate::extension::KnownValue;
58
59use super::envelope::EnvelopeCase;
60
61/// Support for various queries on envelopes.
62impl Envelope {
63    /// The envelope's subject.
64    ///
65    /// For an envelope with no assertions, returns the same envelope.
66    pub fn subject(&self) -> Self {
67        match self.case() {
68            EnvelopeCase::Node { subject, .. } => subject.clone(),
69            _ => self.clone(),
70        }
71    }
72
73    /// The envelope's assertions.
74    pub fn assertions(&self) -> Vec<Self> {
75        match self.case() {
76            EnvelopeCase::Node { assertions, .. } => assertions.clone(),
77            _ => vec![],
78        }
79    }
80
81    /// `true` if the envelope has at least one assertion, `false` otherwise.
82    pub fn has_assertions(&self) -> bool {
83        match self.case() {
84            EnvelopeCase::Node { assertions, .. } => !assertions.is_empty(),
85            _ => false,
86        }
87    }
88
89    /// If the envelope's subject is an assertion return it, else return `None`.
90    pub fn as_assertion(&self) -> Option<Self> {
91        match self.case() {
92            EnvelopeCase::Assertion(_) => Some(self.clone()),
93            _ => None,
94        }
95    }
96
97    /// If the envelope's subject is an assertion return it, else return an error.
98    pub fn try_assertion(&self) -> anyhow::Result<Self> {
99        self.as_assertion().ok_or(Error::NotAssertion.into())
100    }
101
102    /// The envelope's predicate, or `None` if the envelope is not an assertion.
103    pub fn as_predicate(&self) -> Option<Self> {
104        match self.case() {
105            EnvelopeCase::Assertion(assertion) => Some(assertion.predicate()),
106            _ => None,
107        }
108    }
109
110    /// The envelope's predicate, or an error if the envelope is not an assertion.
111    pub fn try_predicate(&self) -> anyhow::Result<Self> {
112        self.as_predicate().ok_or(Error::NotAssertion.into())
113    }
114
115    /// The envelope's object, or `None` if the envelope is not an assertion.
116    pub fn as_object(&self) -> Option<Self> {
117        match self.case() {
118            EnvelopeCase::Assertion(assertion) => Some(assertion.object()),
119            _ => None,
120        }
121    }
122
123    /// The envelope's object, or an error if the envelope is not an assertion.
124    pub fn try_object(&self) -> anyhow::Result<Self> {
125        self.as_object().ok_or(Error::NotAssertion.into())
126    }
127
128    /// The envelope's leaf CBOR object, or `None` if the envelope is not a leaf.
129    pub fn as_leaf(&self) -> Option<CBOR> {
130        match self.case() {
131            EnvelopeCase::Leaf { cbor, .. } => Some(cbor.clone()),
132            _ => None,
133        }
134    }
135
136    /// The envelope's leaf CBOR object, or an error if the envelope is not a leaf.
137    pub fn try_leaf(&self) -> anyhow::Result<CBOR> {
138        self.as_leaf().ok_or(Error::NotLeaf.into())
139    }
140
141    /// The envelope's leaf CBOR object as a CBOR byte string, or an error if
142    /// the envelope is not a leaf, or the leaf is not a byte string.
143    pub fn try_byte_string(&self) -> anyhow::Result<Vec<u8>> {
144        Ok(self.try_leaf()?.try_into_byte_string()?)
145    }
146
147    /// The envelope's `KnownValue`, or `None` if the envelope is not case
148    /// `::KnownValue`.
149    #[cfg(feature = "known_value")]
150    pub fn as_known_value(&self) -> Option<&KnownValue> {
151        match self.case() {
152            EnvelopeCase::KnownValue { value, .. } => Some(value),
153            _ => None,
154        }
155    }
156
157    /// The envelope's `KnownValue`, or an error if the envelope is not case
158    /// `::KnownValue`.
159    #[cfg(feature = "known_value")]
160    pub fn try_known_value(&self) -> anyhow::Result<&KnownValue> {
161        self.as_known_value().ok_or(Error::NotKnownValue.into())
162    }
163
164    /// `true` if the envelope is case `::Leaf`, `false` otherwise.
165    pub fn is_leaf(&self) -> bool {
166        matches!(self.case(), EnvelopeCase::Leaf { .. })
167    }
168
169    /// `true` if the envelope is case `::Node`, `false` otherwise.
170    pub fn is_node(&self) -> bool {
171        matches!(self.case(), EnvelopeCase::Node { .. })
172    }
173
174    /// `true` if the envelope is case `::Wrapped`, `false` otherwise.
175    pub fn is_wrapped(&self) -> bool {
176        matches!(self.case(), EnvelopeCase::Wrapped { .. })
177    }
178
179    /// `true` if the envelope is case `::KnownValue`, `false` otherwise.
180    #[cfg(feature = "known_value")]
181    pub fn is_known_value(&self) -> bool {
182        matches!(self.case(), EnvelopeCase::KnownValue { .. })
183    }
184
185    /// `true` if the envelope is case `::Assertion`, `false` otherwise.
186    pub fn is_assertion(&self) -> bool {
187        matches!(self.case(), EnvelopeCase::Assertion(_))
188    }
189
190    /// `true` if the envelope is case `::Encrypted`, `false` otherwise.
191    #[cfg(feature = "encrypt")]
192    pub fn is_encrypted(&self) -> bool {
193        matches!(self.case(), EnvelopeCase::Encrypted(_))
194    }
195
196    /// `true` if the envelope is case `::Compressed`, `false` otherwise.
197    #[cfg(feature = "compress")]
198    pub fn is_compressed(&self) -> bool {
199        matches!(self.case(), EnvelopeCase::Compressed(_))
200    }
201
202    /// `true` if the envelope is case `::Elided`, `false` otherwise.
203    pub fn is_elided(&self) -> bool {
204        matches!(self.case(), EnvelopeCase::Elided(_))
205    }
206
207    /// `true` if the subject of the envelope is an assertion, `false`
208    /// otherwise.
209    pub fn is_subject_assertion(&self) -> bool {
210        match self.case() {
211            EnvelopeCase::Assertion(_) => true,
212            EnvelopeCase::Node { subject, .. } => subject.is_subject_assertion(),
213            _ => false,
214        }
215    }
216
217    /// `true` if the subject of the envelope has been encrypted, `false`
218    /// otherwise.
219    #[cfg(feature = "encrypt")]
220    pub fn is_subject_encrypted(&self) -> bool {
221        match self.case() {
222            EnvelopeCase::Encrypted(_) => true,
223            EnvelopeCase::Node { subject, .. } => subject.is_subject_encrypted(),
224            _ => false,
225        }
226    }
227
228    /// `true` if the subject of the envelope has been compressed, `false`
229    /// otherwise.
230    #[cfg(feature = "compress")]
231    pub fn is_subject_compressed(&self) -> bool {
232        match self.case() {
233            EnvelopeCase::Compressed(_) => true,
234            EnvelopeCase::Node { subject, .. } => subject.is_subject_compressed(),
235            _ => false,
236        }
237    }
238
239    /// `true` if the subject of the envelope has been elided, `false`
240    /// otherwise.
241    pub fn is_subject_elided(&self) -> bool {
242        match self.case() {
243            EnvelopeCase::Elided(_) => true,
244            EnvelopeCase::Node { subject, .. } => subject.is_subject_elided(),
245            _ => false,
246        }
247    }
248
249    /// `true` if the subject of the envelope has been encrypted, elided, or
250    /// compressed, `false` otherwise.
251    ///
252    /// Obscured assertion envelopes may exist in the list of an envelope's
253    /// assertions.
254    pub fn is_subject_obscured(&self) -> bool {
255        if self.is_subject_elided() {
256            return true;
257        }
258        #[cfg(feature = "encrypt")]
259        if self.is_subject_encrypted() {
260            return true;
261        }
262        #[cfg(feature = "compress")]
263        if self.is_subject_compressed() {
264            return true;
265        }
266        false
267    }
268
269    /// `true` if the envelope is *internal*, that is, it has child elements, or
270    /// `false` if it is a leaf node.
271    ///
272    /// Internal elements include `.node`, `.wrapped`, and `.assertion`.
273    pub fn is_internal(&self) -> bool {
274        matches!(
275            self.case(),
276            EnvelopeCase::Node { .. } | EnvelopeCase::Wrapped { .. } | EnvelopeCase::Assertion(_)
277        )
278    }
279
280    /// `true` if the envelope is encrypted, elided, or compressed; `false`
281    /// otherwise.
282    pub fn is_obscured(&self) -> bool {
283        if self.is_elided() {
284            return true;
285        }
286        #[cfg(feature = "encrypt")]
287        if self.is_encrypted() {
288            return true;
289        }
290        #[cfg(feature = "compress")]
291        if self.is_compressed() {
292            return true;
293        }
294        false
295    }
296
297    /// Returns the envelope's subject, decoded as the given CBOR type.
298    ///
299    /// This method attempts to convert the envelope's subject into the
300    /// requested type `T`. The conversion will succeed if the underlying CBOR
301    /// data can be properly decoded as the specified type.
302    ///
303    /// # Type Parameters
304    ///
305    /// * `T` - The target type to convert the subject into. Must implement
306    ///   `TryFrom<CBOR>`.
307    ///
308    /// # Returns
309    ///
310    /// * `Result<T>` - The decoded subject value or an error if conversion
311    ///   fails
312    ///
313    /// # Errors
314    ///
315    /// * Returns `Error::InvalidFormat` if the encoded type doesn't match the
316    ///   requested type.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use bc_envelope::prelude::*;
322    ///
323    /// // Extract a string
324    /// let envelope = Envelope::new("Hello");
325    /// let text: String = envelope.extract_subject().unwrap();
326    /// assert_eq!(text, "Hello");
327    ///
328    /// // Extract a number
329    /// let envelope = Envelope::new(42);
330    /// let number: i32 = envelope.extract_subject().unwrap();
331    /// assert_eq!(number, 42);
332    ///
333    /// // Extract fails with wrong type
334    /// let envelope = Envelope::new("Not a number");
335    /// let result = envelope.extract_subject::<i32>();
336    /// assert!(result.is_err());
337    /// ```
338    pub fn extract_subject<T>(&self) -> Result<T> where T: Any + TryFrom<CBOR, Error = dcbor::Error> {
339        fn extract_type<T, U>(value: &U) -> Result<T> where T: Any, U: Any + Clone {
340            if TypeId::of::<T>() == TypeId::of::<U>() {
341                let cloned: Box<dyn Any> = Box::new(value.clone());
342                let downcast = cloned.downcast::<T>().unwrap();
343                Ok(*downcast)
344            } else {
345                return Err(Error::InvalidFormat.into());
346            }
347        }
348
349        match self.case() {
350            EnvelopeCase::Wrapped { envelope, .. } => extract_type::<T, Self>(envelope),
351            EnvelopeCase::Node { subject, .. } => subject.extract_subject::<T>(),
352            EnvelopeCase::Leaf { cbor, .. } => {
353                let from_cbor = T::try_from(cbor.clone())?;
354                Ok(from_cbor)
355            }
356            EnvelopeCase::Assertion(assertion) => extract_type::<T, Assertion>(assertion),
357            EnvelopeCase::Elided(digest) => extract_type::<T, Digest>(digest),
358            #[cfg(feature = "known_value")]
359            EnvelopeCase::KnownValue { value, .. } => extract_type::<T, KnownValue>(value),
360            #[cfg(feature = "encrypt")]
361            EnvelopeCase::Encrypted(encrypted_message) =>
362                extract_type::<T, EncryptedMessage>(encrypted_message),
363            #[cfg(feature = "compress")]
364            EnvelopeCase::Compressed(compressed) => extract_type::<T, Compressed>(compressed),
365        }
366    }
367
368    /// Returns all assertions with the given predicate. Match by comparing digests.
369    pub fn assertions_with_predicate(&self, predicate: impl EnvelopeEncodable) -> Vec<Self> {
370        let predicate = Envelope::new(predicate);
371        self.assertions()
372            .into_iter()
373            .filter(|assertion| {
374                assertion
375                    .subject()
376                    .as_predicate()
377                    .map(|p| p.digest() == predicate.digest())
378                    .unwrap_or(false)
379            })
380            .collect()
381    }
382
383    /// Returns the assertion with the given predicate.
384    ///
385    /// Searches the envelope's assertions for one with a predicate matching the
386    /// provided value. The match is determined by comparing the digests of the
387    /// predicates.
388    ///
389    /// # Arguments
390    ///
391    /// * `predicate` - The predicate to search for, can be any type that
392    ///   implements `EnvelopeEncodable`
393    ///
394    /// # Returns
395    ///
396    /// * `Result<Self>` - The matching assertion envelope if found
397    ///
398    /// # Errors
399    ///
400    /// * Returns `EnvelopeError::NonexistentPredicate` if no assertion has the
401    ///   specified predicate
402    /// * Returns `EnvelopeError::AmbiguousPredicate` if multiple assertions
403    ///   have the specified predicate
404    ///
405    /// # Examples
406    ///
407    /// ```
408    /// use bc_envelope::prelude::*;
409    ///
410    /// let envelope = Envelope::new("Person")
411    ///     .add_assertion("name", "Alice")
412    ///     .add_assertion("age", 30);
413    ///
414    /// // Find assertion with predicate "name"
415    /// let name_assertion = envelope.assertion_with_predicate("name").unwrap();
416    /// let name = name_assertion.as_object().unwrap().extract_subject::<String>().unwrap();
417    /// assert_eq!(name, "Alice");
418    ///
419    /// // Trying to find a non-existent predicate produces an error
420    /// assert!(envelope.assertion_with_predicate("address").is_err());
421    /// ```
422    pub fn assertion_with_predicate(
423        &self,
424        predicate: impl EnvelopeEncodable
425    ) -> anyhow::Result<Self> {
426        let a = self.assertions_with_predicate(predicate);
427        if a.is_empty() {
428            bail!(Error::NonexistentPredicate);
429        } else if a.len() == 1 {
430            Ok(a[0].clone())
431        } else {
432            bail!(Error::AmbiguousPredicate);
433        }
434    }
435
436    /// Returns the assertion with the given predicate, or `None` if there is no
437    /// matching predicate.
438    ///
439    /// Returns an error if there are multiple matching predicates.
440    pub fn optional_assertion_with_predicate(
441        &self,
442        predicate: impl EnvelopeEncodable
443    ) -> anyhow::Result<Option<Self>> {
444        let a = self.assertions_with_predicate(predicate);
445        if a.is_empty() {
446            Ok(None)
447        } else if a.len() == 1 {
448            Ok(Some(a[0].clone()))
449        } else {
450            bail!(Error::AmbiguousPredicate);
451        }
452    }
453
454    /// Returns the object of the assertion with the given predicate.
455    ///
456    /// This is a convenience method that finds an assertion with the specified
457    /// predicate and returns its object. It's a common operation when working
458    /// with envelopes that have assertions containing data or metadata.
459    ///
460    /// # Arguments
461    ///
462    /// * `predicate` - The predicate to search for, can be any type that
463    ///   implements `EnvelopeEncodable`
464    ///
465    /// # Returns
466    ///
467    /// * `Result<Self>` - The object part of the matching assertion
468    ///
469    /// # Errors
470    ///
471    /// * Returns `EnvelopeError::NonexistentPredicate` if no assertion has the
472    ///   specified predicate
473    /// * Returns `EnvelopeError::AmbiguousPredicate` if multiple assertions
474    ///   have the specified predicate
475    ///
476    /// # Examples
477    ///
478    /// ```
479    /// use bc_envelope::prelude::*;
480    ///
481    /// let envelope = Envelope::new("Person")
482    ///     .add_assertion("name", "Alice")
483    ///     .add_assertion("age", 30);
484    ///
485    /// // Get the object directly
486    /// let name = envelope.object_for_predicate("name").unwrap();
487    /// assert_eq!(name.extract_subject::<String>().unwrap(), "Alice");
488    ///
489    /// let age = envelope.object_for_predicate("age").unwrap();
490    /// assert_eq!(age.extract_subject::<i32>().unwrap(), 30);
491    /// ```
492    pub fn object_for_predicate(&self, predicate: impl EnvelopeEncodable) -> anyhow::Result<Self> {
493        Ok(self.assertion_with_predicate(predicate)?.as_object().unwrap())
494    }
495
496    /// Returns the envelope decoded as the given type.
497    ///
498    /// This method attempts to convert the envelope into the requested type
499    /// `T`. The conversion will succeed if the envelope can be properly decoded
500    /// as the specified type.
501    pub fn try_as<T>(&self) -> anyhow::Result<T> where T: TryFrom<Envelope, Error = anyhow::Error> {
502        self.clone().try_into()
503    }
504
505    /// Returns the object of the assertion with the given predicate, decoded as
506    /// the given type.
507    ///
508    /// This is a convenience method that finds an assertion with the specified
509    /// predicate and returns its object, decoded as the specified type.
510    pub fn try_object_for_predicate<T>(
511        &self,
512        predicate: impl EnvelopeEncodable
513    ) -> anyhow::Result<T>
514        where T: TryFrom<Envelope, Error = anyhow::Error>
515    {
516        self.object_for_predicate(predicate)?.try_into()
517    }
518
519    /// Returns the object of the assertion with the given predicate, or `None`
520    /// if there is no matching predicate.
521    ///
522    /// Returns an error if there are multiple matching predicates.
523    pub fn optional_object_for_predicate(
524        &self,
525        predicate: impl EnvelopeEncodable
526    ) -> anyhow::Result<Option<Self>> {
527        let a = self.assertions_with_predicate(predicate);
528        if a.is_empty() {
529            Ok(None)
530        } else if a.len() == 1 {
531            Ok(Some(a[0].subject().as_object().unwrap()))
532        } else {
533            bail!(Error::AmbiguousPredicate);
534        }
535    }
536
537    /// Returns the object of the assertion with the given predicate, or `None`
538    /// if there is no matching predicate.
539    pub fn try_optional_object_for_predicate<T>(
540        &self,
541        predicate: impl EnvelopeEncodable
542    ) -> anyhow::Result<Option<T>>
543        where T: TryFrom<Envelope, Error = anyhow::Error>
544    {
545        self.optional_object_for_predicate(predicate)?.map(TryInto::try_into).transpose()
546    }
547
548    /// Returns the object of the assertion, decoded as the given CBOR type.
549    ///
550    /// This method works with assertion envelopes (created with
551    /// `Envelope::new_assertion()`) and extracts the object part of the
552    /// assertion as the specified type.
553    ///
554    /// # Type Parameters
555    ///
556    /// * `T` - The target type to convert the object into. Must implement
557    ///   `TryFrom<CBOR>`.
558    ///
559    /// # Returns
560    ///
561    /// * `Result<T>` - The decoded object value
562    ///
563    /// # Errors
564    ///
565    /// * Returns `EnvelopeError::NotAssertion` if the envelope is not an
566    ///   assertion
567    /// * Returns `Error::InvalidFormat` if the encoded type doesn't match the
568    ///   requested type
569    ///
570    /// # Examples
571    ///
572    /// ```
573    /// use bc_envelope::prelude::*;
574    ///
575    /// // Create an assertion envelope
576    /// let assertion = Envelope::new_assertion("age", 30);
577    ///
578    /// // Extract the object value
579    /// let age: i32 = assertion.extract_object().unwrap();
580    /// assert_eq!(age, 30);
581    ///
582    /// // Not an assertion, gives an error
583    /// let envelope = Envelope::new("Alice");
584    /// assert!(envelope.extract_object::<String>().is_err());
585    /// ```
586    pub fn extract_object<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(&self) -> Result<T> {
587        self.try_object()?.extract_subject()
588    }
589
590    /// Returns the predicate of the assertion, decoded as the given CBOR type.
591    ///
592    /// Returns an error if the envelope is not an assertion. Returns an error
593    /// if the encoded type doesn't match the given type.
594    pub fn extract_predicate<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(&self) -> Result<T> {
595        self.try_predicate()?.extract_subject()
596    }
597
598    /// Returns the object of the assertion with the given predicate, decoded as
599    /// the given CBOR type.
600    ///
601    /// This is a high-level convenience method that combines finding an
602    /// assertion by predicate and extracting its object as a specific type.
603    /// This is particularly useful when working with envelopes containing typed
604    /// data (strings, numbers, etc.) as assertion objects.
605    ///
606    /// # Type Parameters
607    ///
608    /// * `T` - The target type to convert the object into. Must implement
609    ///   `TryFrom<CBOR>`.
610    ///
611    /// # Arguments
612    ///
613    /// * `predicate` - The predicate to search for
614    ///
615    /// # Returns
616    ///
617    /// * `Result<T>` - The decoded object value
618    ///
619    /// # Errors
620    ///
621    /// * Returns `EnvelopeError::NonexistentPredicate` if no assertion has the
622    ///   specified predicate
623    /// * Returns `EnvelopeError::AmbiguousPredicate` if multiple assertions
624    ///   have the specified predicate
625    /// * Returns `Error::InvalidFormat` if the encoded type doesn't match the
626    ///   requested type
627    ///
628    /// # Examples
629    ///
630    /// ```
631    /// use bc_envelope::prelude::*;
632    ///
633    /// let envelope = Envelope::new("Person")
634    ///     .add_assertion("name", "Alice")
635    ///     .add_assertion("age", 30);
636    ///
637    /// // Extract typed values directly
638    /// let name: String = envelope.extract_object_for_predicate("name").unwrap();
639    /// let age: i32 = envelope.extract_object_for_predicate("age").unwrap();
640    ///
641    /// assert_eq!(name, "Alice");
642    /// assert_eq!(age, 30);
643    ///
644    /// // Type mismatch causes an error
645    /// let result = envelope.extract_object_for_predicate::<i32>("name");
646    /// assert!(result.is_err());
647    /// ```
648    pub fn extract_object_for_predicate<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(
649        &self,
650        predicate: impl EnvelopeEncodable
651    ) -> Result<T> {
652        self.assertion_with_predicate(predicate)?.extract_object()
653    }
654
655    /// Returns the object of the assertion with the given predicate decoded as
656    /// the given CBOR type, or `None` if there is no matching predicate.
657    ///
658    /// Returns an error if there are multiple matching predicates.
659    pub fn extract_optional_object_for_predicate<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(
660        &self,
661        predicate: impl EnvelopeEncodable
662    ) -> Result<Option<T>> {
663        self.optional_object_for_predicate(predicate)?.map_or(Ok(None), |o|
664            Ok(Some(o.extract_subject()?))
665        )
666    }
667
668    /// Returns the object of the assertion with the given predicate decoded as
669    /// the given CBOR type, or a default value if there is no matching
670    /// predicate.
671    pub fn extract_object_for_predicate_with_default<
672        T: TryFrom<CBOR, Error = dcbor::Error> + 'static
673    >(&self, predicate: impl EnvelopeEncodable, default: T) -> Result<T> {
674        self.extract_optional_object_for_predicate(predicate)?.map_or(Ok(default), Ok)
675    }
676
677    /// Returns the objects of all assertions with the matching predicate.
678    pub fn objects_for_predicate(&self, predicate: impl EnvelopeEncodable) -> Vec<Self> {
679        self.assertions_with_predicate(predicate)
680            .into_iter()
681            .map(|a| a.as_object().unwrap())
682            .collect()
683    }
684
685    /// Returns the objects of all assertions with the matching predicate,
686    /// decoded as the given CBOR type.
687    ///
688    /// Returns an error if the encoded type doesn't match the given type.
689    pub fn extract_objects_for_predicate<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(
690        &self,
691        predicate: impl EnvelopeEncodable
692    ) -> Result<Vec<T>> {
693        self.objects_for_predicate(predicate)
694            .into_iter()
695            .map(|a| a.extract_subject::<T>())
696            .collect::<Result<Vec<T>>>()
697    }
698
699    /// Returns the objects of all assertions with the matching predicate,
700    /// decoded as the given type.
701    ///
702    /// Returns an error if the encoded type doesn't match the given type.
703    pub fn try_objects_for_predicate<T: TryFrom<Envelope, Error = anyhow::Error> + 'static>(
704        &self,
705        predicate: impl EnvelopeEncodable
706    ) -> anyhow::Result<Vec<T>> {
707        self.objects_for_predicate(predicate)
708            .into_iter()
709            .map(|a| a.try_as::<T>())
710            .collect::<anyhow::Result<Vec<T>>>()
711    }
712
713    /// Returns the number of structural elements in the envelope, including
714    /// itself.
715    pub fn elements_count(&self) -> usize {
716        let mut result = 0;
717
718        fn _count(envelope: &Envelope, result: &mut usize) {
719            *result += 1;
720            match envelope.case() {
721                EnvelopeCase::Node { subject, assertions, .. } => {
722                    *result += subject.elements_count();
723                    for assertion in assertions {
724                        *result += assertion.elements_count();
725                    }
726                }
727                EnvelopeCase::Assertion(assertion) => {
728                    *result += assertion.predicate().elements_count();
729                    *result += assertion.object().elements_count();
730                }
731                EnvelopeCase::Wrapped { envelope, .. } => {
732                    *result += envelope.elements_count();
733                }
734                _ => {}
735            }
736        }
737
738        _count(self, &mut result);
739
740        result
741    }
742}