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