engine/vault/types/
utils.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::vault::{base64::Base64Encodable, crypto_box::BoxProvider};
5
6use serde::{Deserialize, Serialize};
7use std::{
8    cmp::Ordering,
9    fmt::{self, Debug, Display, Formatter},
10    hash::Hash,
11    ops::{Add, AddAssign},
12};
13use thiserror::Error as DeriveError;
14
15/// a record hint.  Used as a hint to what this data is used for.
16#[repr(transparent)]
17#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
18pub struct RecordHint([u8; 24]);
19
20/// A record identifier.  Contains a [`ChainId`] which refers to the transaction.
21#[repr(transparent)]
22#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
23pub struct RecordId(pub(crate) ChainId);
24
25/// Client Id type used to identify a client.
26#[repr(transparent)]
27#[derive(Copy, Clone, Default, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
28pub struct ClientId(pub Id);
29
30/// Vault Id type used to identify a vault.
31#[repr(transparent)]
32#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
33pub struct VaultId(pub Id);
34
35/// A chain identifier.  Used to identify a transaction.
36#[repr(transparent)]
37#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
38pub struct ChainId([u8; 24]);
39
40/// A generic Id type used as the underlying type for the `ClientId` and `VaultId` types.
41#[repr(transparent)]
42#[derive(Copy, Clone, Hash, Default, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
43pub struct Id([u8; 24]);
44
45/// A blob identifier used to refer to a `SealedBlob`.
46#[repr(transparent)]
47#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
48pub struct BlobId([u8; 24]);
49
50/// a big endian encoded number used as a counter.
51#[repr(transparent)]
52#[derive(Copy, Clone, Hash, Eq, PartialEq)]
53pub struct Val([u8; 8]);
54
55#[derive(DeriveError, Debug)]
56#[error("invalid length: expected: `{expected}`, found: `{found}`")]
57pub struct InvalidLength {
58    expected: usize,
59    found: usize,
60}
61
62impl RecordHint {
63    /// create a new random Id for hint
64    pub fn new(hint: impl AsRef<[u8]>) -> Option<Self> {
65        let hint = match hint.as_ref() {
66            hint if hint.len() <= 24 => hint,
67            _ => return None,
68        };
69
70        // copy hint
71        let mut buf = [0; 24];
72        buf[..hint.len()].copy_from_slice(hint);
73        Some(Self(buf))
74    }
75}
76
77impl Val {
78    /// converts a val to a u64.
79    pub fn u64(self) -> u64 {
80        u64::from_be_bytes(self.0)
81    }
82}
83
84impl ChainId {
85    /// Generates a random [`ChainId`]
86    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
87        let mut buf = [0; 24];
88        P::random_buf(&mut buf)?;
89
90        Ok(Self(buf))
91    }
92
93    /// Loads a [`ChainId`] from a buffer of bytes.
94    pub fn load(data: &[u8]) -> Result<Self, InvalidLength> {
95        data.try_into()
96    }
97}
98
99impl BlobId {
100    /// Generates a random [`BlobId`]
101    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
102        let mut buf = [0; 24];
103        P::random_buf(&mut buf)?;
104        Ok(Self(buf))
105    }
106}
107
108impl RecordId {
109    /// Generates a random [`RecordId`]
110    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
111        ChainId::random::<P>().map(RecordId)
112    }
113
114    /// load [`RecordId`] from a buffer of bytes.
115    pub fn load(data: &[u8]) -> Result<Self, InvalidLength> {
116        Ok(RecordId(ChainId::load(data)?))
117    }
118}
119
120impl Id {
121    /// Generates a random [`Id`]
122    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
123        let mut buf = [0; 24];
124        P::random_buf(&mut buf)?;
125
126        Ok(Self(buf))
127    }
128
129    /// load [`Id`] from a buffer of bytes.
130    pub fn load(data: &[u8]) -> Result<Self, InvalidLength> {
131        data.try_into()
132    }
133}
134
135impl VaultId {
136    /// Generates a random [`VaultId`]
137    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
138        Id::random::<P>().map(VaultId)
139    }
140
141    /// load [`VaultId`] from a buffer of bytes.
142    pub fn load(data: &[u8]) -> Result<Self, InvalidLength> {
143        Ok(VaultId(Id::load(data)?))
144    }
145}
146
147impl ClientId {
148    /// Generates a random [`ClientId`]
149    pub fn random<P: BoxProvider>() -> Result<Self, P::Error> {
150        Id::random::<P>().map(ClientId)
151    }
152
153    /// load [`ClientId`] from a buffer of bytes.
154    pub fn load(data: &[u8]) -> Result<Self, InvalidLength> {
155        Ok(ClientId(Id::load(data)?))
156    }
157}
158
159impl AsRef<[u8]> for RecordHint {
160    fn as_ref(&self) -> &[u8] {
161        &self.0
162    }
163}
164impl Debug for RecordHint {
165    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
166        write!(f, "{}", self.0.base64())
167    }
168}
169
170impl From<[u8; 24]> for RecordHint {
171    fn from(bs: [u8; 24]) -> Self {
172        Self(bs)
173    }
174}
175
176impl From<u64> for Val {
177    fn from(num: u64) -> Self {
178        Self(num.to_be_bytes())
179    }
180}
181
182impl PartialOrd for Val {
183    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
184        self.u64().partial_cmp(&other.u64())
185    }
186}
187
188impl Ord for Val {
189    fn cmp(&self, other: &Self) -> Ordering {
190        self.u64().cmp(&other.u64())
191    }
192}
193
194impl Add<u64> for Val {
195    type Output = Self;
196    fn add(self, rhs: u64) -> Self::Output {
197        Self::from(self.u64() + rhs)
198    }
199}
200
201impl AddAssign<u64> for Val {
202    fn add_assign(&mut self, rhs: u64) {
203        *self = *self + rhs;
204    }
205}
206
207impl Debug for Val {
208    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
209        write!(f, "{}", self.u64())
210    }
211}
212
213impl AsRef<[u8]> for ChainId {
214    fn as_ref(&self) -> &[u8] {
215        &self.0
216    }
217}
218
219impl Debug for ChainId {
220    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
221        write!(f, "Chain({})", self.0.base64())
222    }
223}
224
225impl From<RecordId> for ChainId {
226    fn from(id: RecordId) -> Self {
227        id.0
228    }
229}
230
231impl TryFrom<&[u8]> for ChainId {
232    type Error = InvalidLength;
233
234    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
235        if bs.len() != 24 {
236            return Err(InvalidLength {
237                expected: 24,
238                found: bs.len(),
239            });
240        }
241
242        let mut tmp = [0; 24];
243        tmp.copy_from_slice(bs);
244        Ok(Self(tmp))
245    }
246}
247
248impl TryFrom<Vec<u8>> for ChainId {
249    type Error = InvalidLength;
250
251    fn try_from(bs: Vec<u8>) -> Result<Self, Self::Error> {
252        Self::try_from(bs.as_slice())
253    }
254}
255
256impl AsRef<[u8]> for BlobId {
257    fn as_ref(&self) -> &[u8] {
258        &self.0
259    }
260}
261
262impl From<BlobId> for Vec<u8> {
263    fn from(id: BlobId) -> Self {
264        id.0.to_vec()
265    }
266}
267
268impl From<&BlobId> for Vec<u8> {
269    fn from(id: &BlobId) -> Self {
270        id.0.to_vec()
271    }
272}
273
274impl Debug for BlobId {
275    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
276        write!(f, "Blob({})", self.0.base64())
277    }
278}
279
280impl TryFrom<&[u8]> for BlobId {
281    type Error = InvalidLength;
282
283    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
284        if bs.len() != 24 {
285            return Err(InvalidLength {
286                expected: 24,
287                found: bs.len(),
288            });
289        }
290
291        let mut tmp = [0; 24];
292        tmp.copy_from_slice(bs);
293        Ok(Self(tmp))
294    }
295}
296
297impl Debug for RecordId {
298    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
299        write!(f, "Record({})", self.0.as_ref().base64())
300    }
301}
302
303impl Display for RecordId {
304    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
305        write!(f, "{}", self.0.as_ref().base64())
306    }
307}
308
309impl From<ChainId> for RecordId {
310    fn from(id: ChainId) -> Self {
311        RecordId(id)
312    }
313}
314
315impl TryFrom<Vec<u8>> for RecordId {
316    type Error = InvalidLength;
317
318    fn try_from(bs: Vec<u8>) -> Result<Self, Self::Error> {
319        Ok(RecordId(bs.try_into()?))
320    }
321}
322
323impl TryFrom<&[u8]> for RecordId {
324    type Error = InvalidLength;
325
326    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
327        Ok(RecordId(bs.try_into()?))
328    }
329}
330
331impl AsRef<[u8]> for Id {
332    fn as_ref(&self) -> &[u8] {
333        &self.0
334    }
335}
336
337impl Debug for Id {
338    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
339        write!(f, "Chain({})", self.0.base64())
340    }
341}
342
343impl TryFrom<&[u8]> for Id {
344    type Error = InvalidLength;
345
346    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
347        if bs.len() != 24 {
348            return Err(InvalidLength {
349                expected: 24,
350                found: bs.len(),
351            });
352        }
353
354        let mut tmp = [0; 24];
355        tmp.copy_from_slice(bs);
356        Ok(Self(tmp))
357    }
358}
359
360impl TryFrom<Vec<u8>> for Id {
361    type Error = InvalidLength;
362
363    fn try_from(bs: Vec<u8>) -> Result<Self, Self::Error> {
364        Self::try_from(bs.as_slice())
365    }
366}
367
368impl TryFrom<Vec<u8>> for ClientId {
369    type Error = InvalidLength;
370
371    fn try_from(bs: Vec<u8>) -> Result<Self, Self::Error> {
372        Ok(ClientId(bs.try_into()?))
373    }
374}
375
376impl TryFrom<&[u8]> for ClientId {
377    type Error = InvalidLength;
378
379    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
380        Ok(ClientId(bs.try_into()?))
381    }
382}
383
384impl Debug for ClientId {
385    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
386        write!(f, "ClientId({})", self.0.as_ref().base64())
387    }
388}
389
390impl TryFrom<Vec<u8>> for VaultId {
391    type Error = InvalidLength;
392
393    fn try_from(bs: Vec<u8>) -> Result<Self, Self::Error> {
394        Ok(VaultId(bs.try_into()?))
395    }
396}
397
398impl TryFrom<&[u8]> for VaultId {
399    type Error = InvalidLength;
400
401    fn try_from(bs: &[u8]) -> Result<Self, Self::Error> {
402        Ok(VaultId(bs.try_into()?))
403    }
404}
405
406impl Debug for VaultId {
407    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
408        write!(f, "VaultId({})", self.0.as_ref().base64())
409    }
410}
411
412impl Into<Vec<u8>> for VaultId {
413    fn into(self) -> Vec<u8> {
414        self.0 .0.to_vec()
415    }
416}
417
418impl AsRef<[u8]> for VaultId {
419    fn as_ref(&self) -> &[u8] {
420        &self.0 .0
421    }
422}
423
424impl Into<Vec<u8>> for ClientId {
425    fn into(self) -> Vec<u8> {
426        self.0 .0.to_vec()
427    }
428}
429
430impl AsRef<[u8]> for ClientId {
431    fn as_ref(&self) -> &[u8] {
432        &self.0 .0
433    }
434}
435
436impl Into<String> for ClientId {
437    fn into(self) -> String {
438        self.0.as_ref().base64()
439    }
440}
441
442impl Into<String> for VaultId {
443    fn into(self) -> String {
444        self.0.as_ref().base64()
445    }
446}