provenance_mark/
resolution.rs1use std::{
2 convert::TryFrom,
3 ops::{Range, RangeFrom},
4};
5
6use dcbor::{Date, prelude::*};
7use serde::{Deserialize, Serialize};
8
9use crate::{Error, Result, date::SerializableDate};
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
35#[repr(u8)]
36#[serde(into = "u8", try_from = "u8")]
37pub enum ProvenanceMarkResolution {
38 Low = 0,
39 Medium = 1,
40 Quartile = 2,
41 High = 3,
42}
43
44impl From<ProvenanceMarkResolution> for u8 {
45 fn from(res: ProvenanceMarkResolution) -> Self { res as u8 }
46}
47
48impl TryFrom<u8> for ProvenanceMarkResolution {
49 type Error = Error;
50
51 fn try_from(value: u8) -> Result<Self> {
52 match value {
53 0 => Ok(ProvenanceMarkResolution::Low),
54 1 => Ok(ProvenanceMarkResolution::Medium),
55 2 => Ok(ProvenanceMarkResolution::Quartile),
56 3 => Ok(ProvenanceMarkResolution::High),
57 _ => Err(Error::ResolutionError {
58 details: format!(
59 "invalid provenance mark resolution value: {}",
60 value
61 ),
62 }),
63 }
64 }
65}
66
67impl From<ProvenanceMarkResolution> for CBOR {
68 fn from(res: ProvenanceMarkResolution) -> Self { CBOR::from(res as u8) }
69}
70
71impl TryFrom<CBOR> for ProvenanceMarkResolution {
72 type Error = dcbor::Error;
73
74 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
75 let value: u8 = cbor.try_into()?;
76 ProvenanceMarkResolution::try_from(value).map_err(dcbor::Error::from)
77 }
78}
79
80type Res = ProvenanceMarkResolution;
81
82impl ProvenanceMarkResolution {
83 pub fn link_length(&self) -> usize {
84 match self {
85 Res::Low => 4,
86 Res::Medium => 8,
87 Res::Quartile => 16,
88 Res::High => 32,
89 }
90 }
91
92 pub fn seq_bytes_length(&self) -> usize {
93 match self {
94 Res::Low => 2,
95 Res::Medium | Res::Quartile | Res::High => 4,
96 }
97 }
98
99 pub fn date_bytes_length(&self) -> usize {
100 match self {
101 Res::Low => 2,
102 Res::Medium => 4,
103 Res::Quartile | Res::High => 6,
104 }
105 }
106
107 pub fn fixed_length(&self) -> usize {
108 self.link_length() * 3
109 + self.seq_bytes_length()
110 + self.date_bytes_length()
111 }
112
113 pub fn key_range(&self) -> Range<usize> { 0..self.link_length() }
114
115 pub fn chain_id_range(&self) -> Range<usize> { 0..self.link_length() }
116
117 pub fn hash_range(&self) -> Range<usize> {
118 self.chain_id_range().end
119 ..self.chain_id_range().end + self.link_length()
120 }
121
122 pub fn seq_bytes_range(&self) -> Range<usize> {
123 self.hash_range().end..self.hash_range().end + self.seq_bytes_length()
124 }
125
126 pub fn date_bytes_range(&self) -> Range<usize> {
127 self.seq_bytes_range().end
128 ..self.seq_bytes_range().end + self.date_bytes_length()
129 }
130
131 pub fn info_range(&self) -> RangeFrom<usize> {
132 self.date_bytes_range().end..
133 }
134
135 pub fn serialize_date(&self, date: Date) -> Result<Vec<u8>> {
137 match self {
138 Res::Low => date.serialize_2_bytes().map(|bytes| bytes.to_vec()),
139 Res::Medium => date.serialize_4_bytes().map(|bytes| bytes.to_vec()),
140 Res::Quartile | Res::High => {
141 date.serialize_6_bytes().map(|bytes| bytes.to_vec())
142 }
143 }
144 }
145
146 pub fn deserialize_date(&self, data: &[u8]) -> Result<Date> {
148 match self {
149 Res::Low if data.len() == 2 => {
150 Date::deserialize_2_bytes(&[data[0], data[1]])
151 }
152 Res::Medium if data.len() == 4 => {
153 Date::deserialize_4_bytes(&[data[0], data[1], data[2], data[3]])
154 }
155 Res::Quartile | Res::High if data.len() == 6 => {
156 Date::deserialize_6_bytes(&[
157 data[0], data[1], data[2], data[3], data[4], data[5],
158 ])
159 }
160 _ => Err(Error::ResolutionError {
161 details: format!(
162 "invalid date length: expected 2, 4, or 6 bytes, got {}",
163 data.len()
164 ),
165 }),
166 }
167 }
168
169 pub fn serialize_seq(&self, seq: u32) -> Result<Vec<u8>> {
171 match self.seq_bytes_length() {
172 2 => {
173 if seq > (u16::MAX as u32) {
174 return Err(Error::ResolutionError {
175 details: format!(
176 "sequence number {} out of range for 2-byte format (max {})",
177 seq,
178 u16::MAX
179 ),
180 });
181 }
182 Ok((seq as u16).to_be_bytes().to_vec())
183 }
184 4 => Ok(seq.to_be_bytes().to_vec()),
185 _ => unreachable!(),
186 }
187 }
188
189 pub fn deserialize_seq(&self, data: &[u8]) -> Result<u32> {
191 match self.seq_bytes_length() {
192 2 if data.len() == 2 => {
193 Ok(u32::from(u16::from_be_bytes([data[0], data[1]])))
194 }
195 4 if data.len() == 4 => {
196 Ok(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
197 }
198 _ => Err(Error::ResolutionError {
199 details: format!(
200 "invalid sequence number length: expected 2 or 4 bytes, got {}",
201 data.len()
202 ),
203 }),
204 }
205 }
206}
207
208impl std::fmt::Display for ProvenanceMarkResolution {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 match self {
211 Res::Low => write!(f, "low"),
212 Res::Medium => write!(f, "medium"),
213 Res::Quartile => write!(f, "quartile"),
214 Res::High => write!(f, "high"),
215 }
216 }
217}