bc-envelope-pattern 0.14.0

Pattern matcher for Gordian Envelope
Documentation
use bc_components::tags;
use bc_envelope::prelude::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Seed {
    data: Vec<u8>,
    name: String,
    note: String,
    creation_date: Option<Date>,
}

impl Seed {
    pub fn new<T>(data: T) -> Self
    where
        T: AsRef<[u8]>,
    {
        Self::new_opt(data, String::new(), String::new(), None)
    }

    pub fn new_opt<T, S, U>(
        data: T,
        name: S,
        note: U,
        creation_date: Option<Date>,
    ) -> Self
    where
        T: AsRef<[u8]>,
        S: AsRef<str>,
        U: AsRef<str>,
    {
        Self {
            data: data.as_ref().to_vec(),
            name: name.as_ref().to_string(),
            note: note.as_ref().to_string(),
            creation_date,
        }
    }

    pub fn data(&self) -> &[u8] { &self.data }

    pub fn name(&self) -> &str { &self.name }

    pub fn set_name(&mut self, name: impl AsRef<str>) {
        self.name = name.as_ref().to_string();
    }

    pub fn note(&self) -> &str { &self.note }

    pub fn set_note(&mut self, note: impl AsRef<str>) {
        self.note = note.as_ref().to_string();
    }

    pub fn creation_date(&self) -> Option<Date> { self.creation_date }

    pub fn set_creation_date(&mut self, creation_date: Option<Date>) {
        self.creation_date = creation_date;
    }
}

impl CBORTagged for Seed {
    fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_SEED]) }
}

impl From<Seed> for CBOR {
    fn from(value: Seed) -> Self { value.tagged_cbor() }
}

impl CBORTaggedEncodable for Seed {
    fn untagged_cbor(&self) -> CBOR {
        let mut map = Map::new();
        map.insert(1, CBOR::to_byte_string(self.data()));
        if let Some(creation_date) = self.creation_date() {
            map.insert(2, creation_date);
        }
        if !self.name().is_empty() {
            map.insert(3, self.name());
        }
        if !self.note().is_empty() {
            map.insert(4, self.note());
        }
        map.into()
    }
}

impl TryFrom<CBOR> for Seed {
    type Error = dcbor::Error;

    fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
        Self::from_tagged_cbor(cbor)
    }
}

impl CBORTaggedDecodable for Seed {
    fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
        let map = cbor.try_into_map()?;
        let data = map
            .extract::<i32, CBOR>(1)?
            .try_into_byte_string()?
            .to_vec();
        if data.is_empty() {
            return Err("invalid seed data".into());
        }
        let creation_date = map.get::<i32, Date>(2);
        let name = map.get::<i32, String>(3).unwrap_or_default();
        let note = map.get::<i32, String>(4).unwrap_or_default();
        Ok(Self::new_opt(data, name, note, creation_date))
    }
}

impl From<Seed> for Envelope {
    fn from(seed: Seed) -> Self {
        let mut e = Envelope::new(CBOR::to_byte_string(seed.data()))
            .add_type(known_values::SEED_TYPE)
            .add_optional_assertion(known_values::DATE, seed.creation_date());

        if !seed.name().is_empty() {
            e = e.add_assertion(known_values::NAME, seed.name());
        }

        if !seed.note().is_empty() {
            e = e.add_assertion(known_values::NOTE, seed.note());
        }

        e
    }
}

impl TryFrom<Envelope> for Seed {
    type Error = dcbor::Error;

    fn try_from(envelope: Envelope) -> dcbor::Result<Self> {
        envelope.check_type_value(&known_values::SEED_TYPE)?;
        let data = envelope
            .subject()
            .try_leaf()?
            .try_into_byte_string()?
            .to_vec();
        let name = envelope
            .extract_optional_object_for_predicate::<String>(
                known_values::NAME,
            )?
            .unwrap_or_default()
            .to_string();
        let note = envelope
            .extract_optional_object_for_predicate::<String>(
                known_values::NOTE,
            )?
            .unwrap_or_default()
            .to_string();
        let creation_date = envelope
            .extract_optional_object_for_predicate::<Date>(
                known_values::DATE,
            )?;
        Ok(Self::new_opt(data, name, note, creation_date))
    }
}