use std::any::{Any, TypeId};
#[cfg(feature = "compress")]
use bc_components::Compressed;
#[cfg(feature = "encrypt")]
use bc_components::EncryptedMessage;
use bc_components::{Digest, DigestProvider};
use dcbor::prelude::*;
use super::envelope::EnvelopeCase;
#[cfg(feature = "known_value")]
use crate::extension::KnownValue;
use crate::{Assertion, Envelope, EnvelopeEncodable, Error, Result};
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 as_assertion(&self) -> Option<Self> {
match self.case() {
EnvelopeCase::Assertion(_) => Some(self.clone()),
_ => None,
}
}
pub fn try_assertion(&self) -> Result<Self> {
self.as_assertion().ok_or(Error::NotAssertion)
}
pub fn as_predicate(&self) -> Option<Self> {
match self.subject().case() {
EnvelopeCase::Assertion(assertion) => Some(assertion.predicate()),
_ => None,
}
}
pub fn try_predicate(&self) -> Result<Self> {
self.as_predicate().ok_or(Error::NotAssertion)
}
pub fn as_object(&self) -> Option<Self> {
match self.subject().case() {
EnvelopeCase::Assertion(assertion) => Some(assertion.object()),
_ => None,
}
}
pub fn try_object(&self) -> Result<Self> {
self.as_object().ok_or(Error::NotAssertion)
}
pub fn as_leaf(&self) -> Option<CBOR> {
match self.case() {
EnvelopeCase::Leaf { cbor, .. } => Some(cbor.clone()),
_ => None,
}
}
pub fn try_leaf(&self) -> Result<CBOR> {
self.as_leaf().ok_or(Error::NotLeaf)
}
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_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 { .. })
}
}
impl Envelope {
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) -> Result<T>
where
T: Any + TryFrom<CBOR, Error = dcbor::Error>,
{
fn extract_type<T, U>(value: &U) -> 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 {
Err(Error::InvalidFormat)
}
}
match self.case() {
EnvelopeCase::Wrapped { envelope, .. } => {
extract_type::<T, Self>(envelope)
}
EnvelopeCase::Node { subject, .. } => {
subject.extract_subject::<T>()
}
EnvelopeCase::Leaf { cbor, .. } => {
let from_cbor = T::try_from(cbor.clone())?;
Ok(from_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
.subject()
.as_predicate()
.map(|p| p.digest() == predicate.digest())
.unwrap_or(false)
})
.collect()
}
pub fn assertion_with_predicate(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Self> {
let a = self.assertions_with_predicate(predicate);
if a.is_empty() {
Err(Error::NonexistentPredicate)
} else if a.len() == 1 {
Ok(a[0].clone())
} else {
Err(Error::AmbiguousPredicate)
}
}
pub fn optional_assertion_with_predicate(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Option<Self>> {
let a = self.assertions_with_predicate(predicate);
if a.is_empty() {
Ok(None)
} else if a.len() == 1 {
Ok(Some(a[0].clone()))
} else {
Err(Error::AmbiguousPredicate)
}
}
pub fn object_for_predicate(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Self> {
Ok(self
.assertion_with_predicate(predicate)?
.as_object()
.unwrap())
}
pub fn try_as<T>(&self) -> Result<T>
where
T: TryFrom<Envelope, Error = Error>,
{
self.clone().try_into()
}
pub fn try_object_for_predicate<T>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<T>
where
T: TryFrom<Envelope, Error = Error>,
{
self.object_for_predicate(predicate)?.try_into()
}
pub fn optional_object_for_predicate(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Option<Self>> {
let a = self.assertions_with_predicate(predicate);
if a.is_empty() {
Ok(None)
} else if a.len() == 1 {
Ok(Some(a[0].subject().as_object().unwrap()))
} else {
Err(Error::AmbiguousPredicate)
}
}
pub fn try_optional_object_for_predicate<T>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Option<T>>
where
T: TryFrom<Envelope, Error = Error>,
{
self.optional_object_for_predicate(predicate)?
.map(TryInto::try_into)
.transpose()
}
pub fn extract_object<T: TryFrom<CBOR, Error = dcbor::Error> + 'static>(
&self,
) -> Result<T> {
self.try_object()?.extract_subject()
}
pub fn extract_predicate<
T: TryFrom<CBOR, Error = dcbor::Error> + 'static,
>(
&self,
) -> Result<T> {
self.try_predicate()?.extract_subject()
}
pub fn extract_object_for_predicate<
T: TryFrom<CBOR, Error = dcbor::Error> + 'static,
>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<T> {
self.assertion_with_predicate(predicate)?.extract_object()
}
pub fn extract_optional_object_for_predicate<
T: TryFrom<CBOR, Error = dcbor::Error> + 'static,
>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Option<T>> {
self.optional_object_for_predicate(predicate)?
.map_or(Ok(None), |o| Ok(Some(o.extract_subject()?)))
}
pub fn extract_object_for_predicate_with_default<
T: TryFrom<CBOR, Error = dcbor::Error> + 'static,
>(
&self,
predicate: impl EnvelopeEncodable,
default: T,
) -> Result<T> {
self.extract_optional_object_for_predicate(predicate)?
.map_or(Ok(default), Ok)
}
pub fn objects_for_predicate(
&self,
predicate: impl EnvelopeEncodable,
) -> Vec<Self> {
self.assertions_with_predicate(predicate)
.into_iter()
.map(|a| a.as_object().unwrap())
.collect()
}
pub fn extract_objects_for_predicate<
T: TryFrom<CBOR, Error = dcbor::Error> + 'static,
>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Vec<T>> {
self.objects_for_predicate(predicate)
.into_iter()
.map(|a| a.extract_subject::<T>())
.collect::<Result<Vec<T>>>()
}
pub fn try_objects_for_predicate<
T: TryFrom<Envelope, Error = Error> + 'static,
>(
&self,
predicate: impl EnvelopeEncodable,
) -> Result<Vec<T>> {
self.objects_for_predicate(predicate)
.into_iter()
.map(|a| a.try_as::<T>())
.collect::<Result<Vec<T>>>()
}
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
}
}
#[cfg(feature = "known_value")]
impl Envelope {
pub fn set_position(&mut self, position: usize) -> Result<Self> {
let position_assertions =
self.assertions_with_predicate(known_values::POSITION);
if position_assertions.len() > 1 {
return Err(Error::InvalidFormat);
}
let mut e =
if let Some(position_assertion) = position_assertions.first() {
self.remove_assertion(position_assertion.clone())
} else {
self.clone()
};
e = e.add_assertion(known_values::POSITION, position);
Ok(e)
}
pub fn position(&self) -> Result<usize> {
let position_envelope =
self.object_for_predicate(known_values::POSITION)?;
let position = position_envelope.extract_subject::<usize>()?;
Ok(position)
}
pub fn remove_position(&self) -> Result<Self> {
let position_assertions =
self.assertions_with_predicate(known_values::POSITION);
if position_assertions.len() > 1 {
return Err(Error::InvalidFormat);
}
if let Some(position_assertion) = position_assertions.first() {
Ok(self.remove_assertion(position_assertion.clone()))
} else {
Ok(self.clone())
}
}
}