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