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}