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