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))
}
}