#[cfg(not(feature = "multithreaded"))]
use std::rc::Rc as RefCounted;
#[cfg(feature = "multithreaded")]
use std::sync::Arc as RefCounted;
#[cfg(feature = "compress")]
use bc_components::Compressed;
#[cfg(feature = "encrypt")]
use bc_components::EncryptedMessage;
use bc_components::{Digest, DigestProvider};
use dcbor::prelude::*;
#[cfg(feature = "known_value")]
use crate::extension::KnownValue;
use crate::{EnvelopeEncodable, Error, Result, base::Assertion};
#[derive(Debug, Clone, Eq)]
pub struct Envelope(RefCounted<EnvelopeCase>);
impl Envelope {
pub fn case(&self) -> &EnvelopeCase { &self.0 }
}
impl From<EnvelopeCase> for Envelope {
fn from(case: EnvelopeCase) -> Self { Self(RefCounted::new(case)) }
}
impl From<&Envelope> for Envelope {
fn from(envelope: &Envelope) -> Self { envelope.clone() }
}
#[derive(Debug, PartialEq, Eq)]
pub enum EnvelopeCase {
Node {
subject: Envelope,
assertions: Vec<Envelope>,
digest: Digest,
},
Leaf {
cbor: CBOR,
digest: Digest,
},
Wrapped {
envelope: Envelope,
digest: Digest,
},
Assertion(Assertion),
Elided(Digest),
#[cfg(feature = "known_value")]
KnownValue {
value: KnownValue,
digest: Digest,
},
#[cfg(feature = "encrypt")]
Encrypted(EncryptedMessage),
#[cfg(feature = "compress")]
Compressed(Compressed),
}
impl Envelope {
pub fn new(subject: impl EnvelopeEncodable) -> Self {
subject.into_envelope()
}
pub fn new_or_null(subject: Option<impl EnvelopeEncodable>) -> Self {
subject.map_or_else(Self::null, Self::new)
}
pub fn new_or_none(
subject: Option<impl EnvelopeEncodable>,
) -> Option<Self> {
subject.map(Self::new)
}
pub fn new_assertion(
predicate: impl EnvelopeEncodable,
object: impl EnvelopeEncodable,
) -> Self {
Self::new_with_assertion(Assertion::new(predicate, object))
}
}
impl Envelope {
pub(crate) fn new_with_unchecked_assertions(
subject: Self,
unchecked_assertions: Vec<Self>,
) -> Self {
assert!(!unchecked_assertions.is_empty());
let mut sorted_assertions = unchecked_assertions;
sorted_assertions.sort_by_key(|a| a.digest());
let mut digests = vec![subject.digest()];
digests.extend(sorted_assertions.iter().map(|a| a.digest()));
let digest = Digest::from_digests(&digests);
(EnvelopeCase::Node { subject, assertions: sorted_assertions, digest })
.into()
}
pub(crate) fn new_with_assertions(
subject: Self,
assertions: Vec<Self>,
) -> Result<Self> {
if !assertions
.iter()
.all(|a| a.is_subject_assertion() || a.is_subject_obscured())
{
return Err(Error::InvalidFormat);
}
Ok(Self::new_with_unchecked_assertions(subject, assertions))
}
pub(crate) fn new_with_assertion(assertion: Assertion) -> Self {
EnvelopeCase::Assertion(assertion).into()
}
#[cfg(feature = "known_value")]
pub(crate) fn new_with_known_value(value: KnownValue) -> Self {
let digest = value.digest();
(EnvelopeCase::KnownValue { value, digest }).into()
}
#[cfg(feature = "encrypt")]
pub(crate) fn new_with_encrypted(
encrypted_message: EncryptedMessage,
) -> Result<Self> {
if !encrypted_message.has_digest() {
return Err(Error::MissingDigest);
}
Ok(EnvelopeCase::Encrypted(encrypted_message).into())
}
#[cfg(feature = "compress")]
pub(crate) fn new_with_compressed(compressed: Compressed) -> Result<Self> {
if !compressed.has_digest() {
return Err(Error::MissingDigest);
}
Ok(EnvelopeCase::Compressed(compressed).into())
}
pub(crate) fn new_elided(digest: Digest) -> Self {
EnvelopeCase::Elided(digest).into()
}
pub(crate) fn new_leaf(value: impl Into<CBOR>) -> Self {
let cbor: CBOR = value.into();
let digest = Digest::from_image(cbor.to_cbor_data());
(EnvelopeCase::Leaf { cbor, digest }).into()
}
pub(crate) fn new_wrapped(envelope: Self) -> Self {
let digest = Digest::from_digests(&[envelope.digest()]);
(EnvelopeCase::Wrapped { envelope, digest }).into()
}
}
impl AsRef<Envelope> for Envelope {
fn as_ref(&self) -> &Envelope { self }
}
#[cfg(test)]
mod tests {
#[cfg(feature = "compress")]
use bc_components::Compressed;
use bc_components::DigestProvider;
#[cfg(feature = "known_value")]
use crate::extension::KnownValue;
use crate::{Assertion, Envelope};
#[test]
fn test_any_envelope() {
let e1 = Envelope::new_leaf("Hello");
let e2 = Envelope::new("Hello");
assert_eq!(e1.format(), e2.format());
assert_eq!(e1.digest(), e2.digest());
}
#[cfg(feature = "known_value")]
#[test]
fn test_any_known_value() {
let known_value = KnownValue::new(100);
let e1 = Envelope::new_with_known_value(known_value.clone());
let e2 = Envelope::new(known_value);
assert_eq!(e1.format(), e2.format());
assert_eq!(e1.digest(), e2.digest());
}
#[test]
fn test_any_assertion() {
let assertion = Assertion::new("knows", "Bob");
let e1 = Envelope::new_with_assertion(assertion.clone());
let e2 = Envelope::new(assertion);
assert_eq!(e1.format(), e2.format());
assert_eq!(e1.digest(), e2.digest());
}
#[test]
fn test_any_encrypted() {
}
#[cfg(feature = "compress")]
#[test]
fn test_any_compressed() {
let data = "Hello".as_bytes();
let digest = data.digest();
let compressed = Compressed::from_decompressed_data(data, Some(digest));
let e1 = Envelope::new_with_compressed(compressed.clone()).unwrap();
let e2 = Envelope::try_from(compressed).unwrap();
assert_eq!(e1.format(), e2.format());
assert_eq!(e1.digest(), e2.digest());
}
#[test]
fn test_any_cbor_encodable() {
let e1 = Envelope::new_leaf(1);
let e2 = Envelope::new(1);
assert_eq!(e1.format(), e2.format());
assert_eq!(e1.digest(), e2.digest());
}
}