use anyhow::bail;
use bc_components::{Digest, DigestProvider};
#[cfg(feature = "encrypt")]
use bc_components::EncryptedMessage;
#[cfg(feature = "compress")]
use bc_components::Compressed;
use dcbor::prelude::*;
use std::any::{Any, TypeId};
use crate::{Assertion, Envelope, EnvelopeError, EnvelopeEncodable};
#[cfg(feature = "known_value")]
use crate::extension::KnownValue;
use super::envelope::EnvelopeCase;
impl Envelope {
pub fn subject(&self) -> Self {
match self.case() {
EnvelopeCase::Node { subject, .. } => subject.clone(),
_ => self.clone(),
}
}
pub fn assertions(&self) -> Vec<Self> {
match self.case() {
EnvelopeCase::Node { assertions, .. } => assertions.clone(),
_ => vec![],
}
}
pub fn has_assertions(&self) -> bool {
match self.case() {
EnvelopeCase::Node { assertions, .. } => !assertions.is_empty(),
_ => false,
}
}
pub fn assertion(&self) -> Option<Self> {
match self.case() {
EnvelopeCase::Assertion(_) => Some(self.clone()),
_ => None,
}
}
pub fn expect_assertion(&self) -> Result<Self, EnvelopeError> {
self.assertion().ok_or(EnvelopeError::NotAssertion)
}
pub fn predicate(&self) -> Option<Self> {
match self.case() {
EnvelopeCase::Assertion(assertion) => Some(assertion.predicate()),
_ => None,
}
}
pub fn expect_predicate(&self) -> Result<Self, EnvelopeError> {
self.predicate().ok_or(EnvelopeError::NotAssertion)
}
pub fn object(&self) -> Option<Self> {
match self.case() {
EnvelopeCase::Assertion(assertion) => Some(assertion.object()),
_ => None,
}
}
pub fn expect_object(&self) -> Result<Self, EnvelopeError> {
self.object().ok_or(EnvelopeError::NotAssertion)
}
pub fn leaf(&self) -> Option<&CBOR> {
match self.case() {
EnvelopeCase::Leaf { cbor, .. } => Some(cbor),
_ => None,
}
}
pub fn expect_leaf(&self) -> Result<&CBOR, EnvelopeError> {
self.leaf().ok_or(EnvelopeError::NotLeaf)
}
#[cfg(feature = "known_value")]
pub fn known_value(&self) -> Option<&KnownValue> {
match self.case() {
EnvelopeCase::KnownValue { value, .. } => Some(value),
_ => None,
}
}
#[cfg(feature = "known_value")]
pub fn expect_known_value(&self) -> Result<&KnownValue, EnvelopeError> {
self.known_value().ok_or(EnvelopeError::NotKnownValue)
}
pub fn is_leaf(&self) -> bool {
matches!(self.case(), EnvelopeCase::Leaf { .. })
}
pub fn is_node(&self) -> bool {
matches!(self.case(), EnvelopeCase::Node { .. })
}
pub fn is_wrapped(&self) -> bool {
matches!(self.case(), EnvelopeCase::Wrapped { .. })
}
#[cfg(feature = "known_value")]
pub fn is_known_value(&self) -> bool {
matches!(self.case(), EnvelopeCase::KnownValue { .. })
}
pub fn is_assertion(&self) -> bool {
matches!(self.case(), EnvelopeCase::Assertion(_))
}
#[cfg(feature = "encrypt")]
pub fn is_encrypted(&self) -> bool {
matches!(self.case(), EnvelopeCase::Encrypted(_))
}
#[cfg(feature = "compress")]
pub fn is_compressed(&self) -> bool {
matches!(self.case(), EnvelopeCase::Compressed(_))
}
pub fn is_elided(&self) -> bool {
matches!(self.case(), EnvelopeCase::Elided(_))
}
pub fn is_subject_assertion(&self) -> bool {
match self.case() {
EnvelopeCase::Assertion(_) => true,
EnvelopeCase::Node { subject, .. } => subject.is_subject_assertion(),
_ => false,
}
}
#[cfg(feature = "encrypt")]
pub fn is_subject_encrypted(&self) -> bool {
match self.case() {
EnvelopeCase::Encrypted(_) => true,
EnvelopeCase::Node { subject, .. } => subject.is_subject_encrypted(),
_ => false,
}
}
#[cfg(feature = "compress")]
pub fn is_subject_compressed(&self) -> bool {
match self.case() {
EnvelopeCase::Compressed(_) => true,
EnvelopeCase::Node { subject, .. } => subject.is_subject_compressed(),
_ => false,
}
}
pub fn is_subject_elided(&self) -> bool {
match self.case() {
EnvelopeCase::Elided(_) => true,
EnvelopeCase::Node { subject, .. } => subject.is_subject_elided(),
_ => false,
}
}
pub fn is_subject_obscured(&self) -> bool {
if self.is_subject_elided() {
return true;
}
#[cfg(feature = "encrypt")]
if self.is_subject_encrypted() {
return true;
}
#[cfg(feature = "compress")]
if self.is_subject_compressed() {
return true;
}
false
}
pub fn is_internal(&self) -> bool {
matches!(
self.case(),
EnvelopeCase::Node { .. } | EnvelopeCase::Wrapped { .. } | EnvelopeCase::Assertion(_)
)
}
pub fn is_obscured(&self) -> bool {
if self.is_elided() {
return true;
}
#[cfg(feature = "encrypt")]
if self.is_encrypted() {
return true;
}
#[cfg(feature = "compress")]
if self.is_compressed() {
return true;
}
false
}
pub fn extract_subject<T>(&self) -> anyhow::Result<T>
where
T: Any + CBORDecodable,
{
fn extract_type<T, U>(value: &U) -> anyhow::Result<T>
where
T: Any,
U: Any + Clone,
{
if TypeId::of::<T>() == TypeId::of::<U>() {
let cloned: Box<dyn Any> = Box::new(value.clone());
let downcast = cloned
.downcast::<T>()
.unwrap();
Ok(*downcast)
} else {
bail!(EnvelopeError::InvalidFormat)
}
}
match self.case() {
EnvelopeCase::Wrapped { envelope, .. } => extract_type::<T, Self>(envelope),
EnvelopeCase::Node { subject, .. } => subject.extract_subject::<T>(),
EnvelopeCase::Leaf { cbor, .. } => Ok(T::from_cbor(cbor)?),
EnvelopeCase::Assertion(assertion) => extract_type::<T, Assertion>(assertion),
EnvelopeCase::Elided(digest) => extract_type::<T, Digest>(digest),
#[cfg(feature = "known_value")]
EnvelopeCase::KnownValue { value, .. } => extract_type::<T, KnownValue>(value),
#[cfg(feature = "encrypt")]
EnvelopeCase::Encrypted(encrypted_message) => extract_type::<T, EncryptedMessage>(encrypted_message),
#[cfg(feature = "compress")]
EnvelopeCase::Compressed(compressed) => extract_type::<T, Compressed>(compressed),
}
}
pub fn assertions_with_predicate(&self, predicate: impl EnvelopeEncodable) -> Vec<Self> {
let predicate = Envelope::new(predicate);
self.assertions()
.into_iter()
.filter(|assertion| {
assertion
.predicate()
.map(|p| p.digest() == predicate.digest())
.unwrap_or(false)
})
.collect()
}
pub fn assertion_with_predicate(&self, predicate: impl EnvelopeEncodable) -> Result<Self, EnvelopeError> {
let a = self.assertions_with_predicate(predicate);
if a.is_empty() {
Err(EnvelopeError::NonexistentPredicate)
} else if a.len() == 1 {
Ok(a[0].clone())
} else {
Err(EnvelopeError::AmbiguousPredicate)
}
}
pub fn object_for_predicate(&self, predicate: impl EnvelopeEncodable) -> Result<Self, EnvelopeError> {
Ok(self.assertion_with_predicate(predicate)?.object().unwrap())
}
pub fn extract_object_for_predicate<T: CBORDecodable + 'static>(&self, predicate: impl EnvelopeEncodable) -> anyhow::Result<T> {
self.assertion_with_predicate(predicate)?
.object()
.unwrap()
.extract_subject()
}
pub fn extract_optional_object_for_predicate<T: CBORDecodable + 'static>(&self, predicate: impl EnvelopeEncodable) -> anyhow::Result<Option<T>> {
if let Ok(object) = self.object_for_predicate(predicate) {
Ok(Some(object.extract_subject()?))
} else {
Ok(None)
}
}
pub fn objects_for_predicate(&self, predicate: impl EnvelopeEncodable) -> Vec<Self> {
self.assertions_with_predicate(predicate)
.into_iter()
.map(|a| a.object().unwrap())
.collect()
}
pub fn extract_objects_for_predicate<T: CBORDecodable>(&self, predicate: impl EnvelopeEncodable) -> anyhow::Result<Vec<T>> {
self.assertions_with_predicate(predicate)
.into_iter()
.map(|a| a.object().unwrap().extract_subject())
.collect()
}
pub fn elements_count(&self) -> usize {
let mut result = 0;
fn _count(envelope: &Envelope, result: &mut usize) {
*result += 1;
match envelope.case() {
EnvelopeCase::Node {
subject,
assertions,
..
} => {
*result += subject.elements_count();
for assertion in assertions {
*result += assertion.elements_count();
}
}
EnvelopeCase::Assertion(assertion) => {
*result += assertion.predicate().elements_count();
*result += assertion.object().elements_count();
}
EnvelopeCase::Wrapped { envelope, .. } => {
*result += envelope.elements_count();
}
_ => {}
}
}
_count(self, &mut result);
result
}
}