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