bc_components/
reference.rs1use std::borrow::Cow;
2
3use anyhow::{Result, bail};
4use bc_ur::prelude::*;
5
6use crate::{Digest, digest_provider::DigestProvider, tags};
7
8pub trait ReferenceProvider {
20 fn reference(&self) -> Reference;
25
26 fn ref_hex(&self) -> String { self.reference().ref_hex() }
31
32 fn ref_data_short(&self) -> [u8; 4] { self.reference().ref_data_short() }
37
38 fn ref_hex_short(&self) -> String { self.reference().ref_hex_short() }
43
44 fn ref_bytewords(&self, prefix: Option<&str>) -> String {
55 self.reference().bytewords_identifier(prefix)
56 }
57
58 fn ref_bytemoji(&self, prefix: Option<&str>) -> String {
68 self.reference().bytemoji_identifier(prefix)
69 }
70}
71
72#[derive(Clone, PartialEq, Eq, Hash)]
88pub struct Reference([u8; Self::REFERENCE_SIZE]);
89
90impl Reference {
91 pub const REFERENCE_SIZE: usize = 32;
92
93 pub fn from_data(data: [u8; Self::REFERENCE_SIZE]) -> Self { Self(data) }
95
96 pub fn from_data_ref(data: impl AsRef<[u8]>) -> Result<Self> {
100 let data = data.as_ref();
101 if data.len() != Self::REFERENCE_SIZE {
102 bail!("Invalid reference size");
103 }
104 let mut arr = [0u8; Self::REFERENCE_SIZE];
105 arr.copy_from_slice(data.as_ref());
106 Ok(Self::from_data(arr))
107 }
108
109 pub fn from_digest(digest: Digest) -> Self {
111 Self::from_data(*digest.data())
112 }
113
114 pub fn data(&self) -> &[u8; Self::REFERENCE_SIZE] { self.into() }
116
117 pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
119
120 pub fn from_hex(hex: impl AsRef<str>) -> Self {
125 Self::from_data_ref(hex::decode(hex.as_ref()).unwrap()).unwrap()
126 }
127
128 pub fn ref_hex(&self) -> String { hex::encode(self.0) }
130
131 pub fn ref_data_short(&self) -> [u8; 4] { self.0[0..4].try_into().unwrap() }
133
134 pub fn ref_hex_short(&self) -> String { hex::encode(self.ref_data_short()) }
136
137 pub fn bytewords_identifier(&self, prefix: Option<&str>) -> String {
139 let s = bytewords::identifier(&self.ref_data_short()).to_uppercase();
140 if let Some(prefix) = prefix {
141 format!("{prefix} {s}")
142 } else {
143 s
144 }
145 }
146
147 pub fn bytemoji_identifier(&self, prefix: Option<&str>) -> String {
149 let s =
150 bytewords::bytemoji_identifier(&self.0[..4].try_into().unwrap())
151 .to_uppercase();
152 if let Some(prefix) = prefix {
153 format!("{prefix} {s}")
154 } else {
155 s
156 }
157 }
158}
159
160impl ReferenceProvider for Reference {
164 fn reference(&self) -> Reference {
165 Reference::from_digest(self.digest().into_owned())
166 }
167}
168
169impl<'a> From<&'a Reference> for &'a [u8; Reference::REFERENCE_SIZE] {
170 fn from(value: &'a Reference) -> Self { &value.0 }
171}
172
173impl<'a> From<&'a Reference> for &'a [u8] {
174 fn from(value: &'a Reference) -> Self { &value.0 }
175}
176
177impl AsRef<[u8]> for Reference {
178 fn as_ref(&self) -> &[u8] { &self.0 }
179}
180
181impl AsRef<Reference> for Reference {
182 fn as_ref(&self) -> &Reference { self }
183}
184
185impl std::cmp::PartialOrd for Reference {
186 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
187 Some(self.0.cmp(&other.0))
188 }
189}
190
191impl std::cmp::Ord for Reference {
192 fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.0.cmp(&other.0) }
193}
194
195impl DigestProvider for Reference {
196 fn digest(&self) -> Cow<'_, Digest> {
197 Cow::Owned(Digest::from_image(self.tagged_cbor().to_cbor_data()))
198 }
199}
200
201impl std::fmt::Debug for Reference {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 write!(f, "Reference({})", self.ref_hex())
204 }
205}
206
207impl std::fmt::Display for Reference {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(f, "Reference({})", self.ref_hex_short())
210 }
211}
212
213impl CBORTagged for Reference {
214 fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_REFERENCE]) }
215}
216
217impl From<Reference> for CBOR {
218 fn from(value: Reference) -> Self { value.tagged_cbor() }
219}
220
221impl CBORTaggedEncodable for Reference {
222 fn untagged_cbor(&self) -> CBOR { CBOR::to_byte_string(self.0) }
223}
224
225impl TryFrom<CBOR> for Reference {
226 type Error = dcbor::Error;
227
228 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
229 Self::from_tagged_cbor(cbor)
230 }
231}
232
233impl CBORTaggedDecodable for Reference {
234 fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
235 let data = CBOR::try_into_byte_string(cbor)?;
236 Ok(Self::from_data_ref(data)?)
237 }
238}
239
240impl From<&Reference> for Reference {
242 fn from(digest: &Reference) -> Self { digest.clone() }
243}
244
245impl From<Reference> for Vec<u8> {
247 fn from(digest: Reference) -> Self { digest.0.to_vec() }
248}
249
250impl From<&Reference> for Vec<u8> {
252 fn from(digest: &Reference) -> Self { digest.0.to_vec() }
253}