bc_components/
reference.rs1use std::borrow::Cow;
2use bc_ur::prelude::*;
3use crate::{ digest_provider::DigestProvider, tags, Digest };
4use anyhow::{ bail, Result };
5
6pub trait ReferenceProvider {
15 fn reference(&self) -> Reference;
20
21 fn ref_hex(&self) -> String {
26 self.reference().ref_hex()
27 }
28
29 fn ref_data_short(&self) -> [u8; 4] {
34 self.reference().ref_data_short()
35 }
36
37 fn ref_hex_short(&self) -> String {
42 self.reference().ref_hex_short()
43 }
44
45 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 {
66 self.reference().bytemoji_identifier(prefix)
67 }
68}
69
70#[derive(Clone, PartialEq, Eq, Hash)]
86pub struct Reference([u8; Self::REFERENCE_SIZE]);
87
88impl Reference {
89 pub const REFERENCE_SIZE: usize = 32;
90
91 pub fn from_data(data: [u8; Self::REFERENCE_SIZE]) -> Self {
93 Self(data)
94 }
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] {
116 self.into()
117 }
118
119 pub fn from_hex(hex: impl AsRef<str>) -> Self {
124 Self::from_data_ref(hex::decode(hex.as_ref()).unwrap()).unwrap()
125 }
126
127 pub fn ref_hex(&self) -> String {
129 hex::encode(self.0)
130 }
131
132 pub fn ref_data_short(&self) -> [u8; 4] {
134 self.0[0..4].try_into().unwrap()
135 }
136
137 pub fn ref_hex_short(&self) -> String {
139 hex::encode(self.ref_data_short())
140 }
141
142 pub fn bytewords_identifier(&self, prefix: Option<&str>) -> String {
144 let s = bytewords::identifier(&self.ref_data_short()).to_uppercase();
145 if let Some(prefix) = prefix {
146 format!("{prefix} {s}")
147 } else {
148 s
149 }
150 }
151
152 pub fn bytemoji_identifier(&self, prefix: Option<&str>) -> String {
154 let s = bytewords::bytemoji_identifier(&self.0[..4].try_into().unwrap()).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 {
174 &value.0
175 }
176}
177
178impl<'a> From<&'a Reference> for &'a [u8] {
179 fn from(value: &'a Reference) -> Self {
180 &value.0
181 }
182}
183
184impl AsRef<[u8]> for Reference {
185 fn as_ref(&self) -> &[u8] {
186 &self.0
187 }
188}
189
190impl AsRef<Reference> for Reference {
191 fn as_ref(&self) -> &Reference {
192 self
193 }
194}
195
196impl std::cmp::PartialOrd for Reference {
197 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
198 Some(self.0.cmp(&other.0))
199 }
200}
201
202impl std::cmp::Ord for Reference {
203 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
204 self.0.cmp(&other.0)
205 }
206}
207
208impl DigestProvider for Reference {
209 fn digest(&self) -> Cow<'_, Digest> {
210 Cow::Owned(Digest::from_image(self.tagged_cbor().to_cbor_data()))
211 }
212}
213
214impl std::fmt::Debug for Reference {
215 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216 write!(f, "Reference({})", self.ref_hex())
217 }
218}
219
220impl std::fmt::Display for Reference {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 write!(f, "Reference({})", self.ref_hex_short())
223 }
224}
225
226impl CBORTagged for Reference {
227 fn cbor_tags() -> Vec<Tag> {
228 tags_for_values(&[tags::TAG_REFERENCE])
229 }
230}
231
232impl From<Reference> for CBOR {
233 fn from(value: Reference) -> Self {
234 value.tagged_cbor()
235 }
236}
237
238impl CBORTaggedEncodable for Reference {
239 fn untagged_cbor(&self) -> CBOR {
240 CBOR::to_byte_string(self.0)
241 }
242}
243
244impl TryFrom<CBOR> for Reference {
245 type Error = dcbor::Error;
246
247 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
248 Self::from_tagged_cbor(cbor)
249 }
250}
251
252impl CBORTaggedDecodable for Reference {
253 fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
254 let data = CBOR::try_into_byte_string(cbor)?;
255 Ok(Self::from_data_ref(data)?)
256 }
257}
258
259impl From<&Reference> for Reference {
261 fn from(digest: &Reference) -> Self {
262 digest.clone()
263 }
264}
265
266impl From<Reference> for Vec<u8> {
268 fn from(digest: Reference) -> Self {
269 digest.0.to_vec()
270 }
271}
272
273impl From<&Reference> for Vec<u8> {
275 fn from(digest: &Reference) -> Self {
276 digest.0.to_vec()
277 }
278}