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