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