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