provenance_mark/
resolution.rsuse std::ops::{ Range, RangeFrom };
use dcbor::{ prelude::*, Date };
use anyhow::{ Result, bail, Error };
use serde::{ Deserialize, Serialize };
use std::convert::TryFrom;
use crate::date::SerializableDate;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
#[serde(into = "u8", try_from = "u8")]
pub enum ProvenanceMarkResolution {
Low = 0,
Medium = 1,
Quartile = 2,
High = 3,
}
impl From<ProvenanceMarkResolution> for u8 {
fn from(res: ProvenanceMarkResolution) -> Self {
res as u8
}
}
impl TryFrom<u8> for ProvenanceMarkResolution {
type Error = Error;
fn try_from(value: u8) -> Result<Self> {
match value {
0 => Ok(ProvenanceMarkResolution::Low),
1 => Ok(ProvenanceMarkResolution::Medium),
2 => Ok(ProvenanceMarkResolution::Quartile),
3 => Ok(ProvenanceMarkResolution::High),
_ => bail!("Invalid provenance mark resolution"),
}
}
}
impl From<ProvenanceMarkResolution> for CBOR {
fn from(res: ProvenanceMarkResolution) -> Self {
CBOR::from(res as u8)
}
}
impl TryFrom<CBOR> for ProvenanceMarkResolution {
type Error = Error;
fn try_from(cbor: CBOR) -> Result<Self> {
let value: u8 = cbor.try_into()?;
ProvenanceMarkResolution::try_from(value)
}
}
type Res = ProvenanceMarkResolution;
impl ProvenanceMarkResolution {
pub fn link_length(&self) -> usize {
match self {
Res::Low => 4,
Res::Medium => 8,
Res::Quartile => 16,
Res::High => 32,
}
}
pub fn seq_bytes_length(&self) -> usize {
match self {
Res::Low => 2,
Res::Medium | Res::Quartile | Res::High => 4,
}
}
pub fn date_bytes_length(&self) -> usize {
match self {
Res::Low => 2,
Res::Medium => 4,
Res::Quartile | Res::High => 6,
}
}
pub fn fixed_length(&self) -> usize {
self.link_length() * 3 + self.seq_bytes_length() + self.date_bytes_length()
}
pub fn key_range(&self) -> Range<usize> {
0..self.link_length()
}
pub fn chain_id_range(&self) -> Range<usize> {
0..self.link_length()
}
pub fn hash_range(&self) -> Range<usize> {
self.chain_id_range().end..self.chain_id_range().end + self.link_length()
}
pub fn seq_bytes_range(&self) -> Range<usize> {
self.hash_range().end..self.hash_range().end + self.seq_bytes_length()
}
pub fn date_bytes_range(&self) -> Range<usize> {
self.seq_bytes_range().end..self.seq_bytes_range().end + self.date_bytes_length()
}
pub fn info_range(&self) -> RangeFrom<usize> {
self.date_bytes_range().end..
}
pub fn serialize_date(&self, date: Date) -> Result<Vec<u8>> {
match self {
Res::Low => date.serialize_2_bytes().map(|bytes| bytes.to_vec()),
Res::Medium => date.serialize_4_bytes().map(|bytes| bytes.to_vec()),
Res::Quartile | Res::High => date.serialize_6_bytes().map(|bytes| bytes.to_vec()),
}
}
pub fn deserialize_date(&self, data: &[u8]) -> Result<Date> {
match self {
Res::Low if data.len() == 2 => Date::deserialize_2_bytes(&[data[0], data[1]]),
Res::Medium if data.len() == 4 =>
Date::deserialize_4_bytes(&[data[0], data[1], data[2], data[3]]),
Res::Quartile | Res::High if data.len() == 6 =>
Date::deserialize_6_bytes(&[data[0], data[1], data[2], data[3], data[4], data[5]]),
_ => bail!("Invalid date length"),
}
}
pub fn serialize_seq(&self, seq: u32) -> Result<Vec<u8>> {
match self.seq_bytes_length() {
2 => {
if seq > (u16::MAX as u32) {
bail!("Sequence number out of range");
}
Ok((seq as u16).to_be_bytes().to_vec())
}
4 => Ok(seq.to_be_bytes().to_vec()),
_ => unreachable!(),
}
}
pub fn deserialize_seq(&self, data: &[u8]) -> Result<u32> {
match self.seq_bytes_length() {
2 if data.len() == 2 => Ok(u32::from(u16::from_be_bytes([data[0], data[1]]))),
4 if data.len() == 4 => Ok(u32::from_be_bytes([data[0], data[1], data[2], data[3]])),
_ => bail!("Invalid sequence number length"),
}
}
}
impl std::fmt::Display for ProvenanceMarkResolution {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Res::Low => write!(f, "low"),
Res::Medium => write!(f, "medium"),
Res::Quartile => write!(f, "quartile"),
Res::High => write!(f, "high"),
}
}
}