ssi_multicodec/
lib.rs

1use std::ops::Deref;
2
3mod codec;
4pub use codec::*;
5
6include!(concat!(env!("OUT_DIR"), "/table.rs"));
7
8#[derive(Debug, Clone, thiserror::Error)]
9pub enum Error {
10    #[error(transparent)]
11    Varint(#[from] unsigned_varint::decode::Error),
12
13    #[error("unexpected codec {0}")]
14    UnexpectedCodec(u64),
15
16    #[error("invalid data")]
17    InvalidData,
18}
19
20/// Multi-encoded byte slice.
21pub struct MultiEncoded([u8]);
22
23impl MultiEncoded {
24    /// Creates a new multi-encoded slice from the given `bytes`.
25    ///
26    /// Following the [`unsigned-varint`] specification and to avoid memory
27    /// attacks, the coded must be encoded on at most 9 bytes (63 bits unsigned
28    /// varint).
29    ///
30    /// [`unsigned-varint`](https://github.com/multiformats/unsigned-varint)
31    #[inline(always)]
32    pub fn new(bytes: &[u8]) -> Result<&Self, Error> {
33        unsigned_varint::decode::u64(bytes)?;
34        Ok(unsafe { std::mem::transmute::<&[u8], &Self>(bytes) })
35    }
36
37    /// Creates a new multi-encoded slice from the given `bytes` without
38    /// checking the codec.
39    ///
40    /// # Safety
41    ///
42    /// Following the [`unsigned-varint`] specification and to avoid memory
43    /// attacks, the coded must be encoded on at most 9 bytes (63 bits unsigned
44    /// varint).
45    ///
46    /// [`unsigned-varint`](https://github.com/multiformats/unsigned-varint)
47    #[inline(always)]
48    pub unsafe fn new_unchecked(bytes: &[u8]) -> &Self {
49        unsafe { std::mem::transmute(bytes) }
50    }
51
52    #[allow(clippy::len_without_is_empty)]
53    pub fn len(&self) -> usize {
54        self.0.len()
55    }
56
57    #[inline(always)]
58    pub fn parts(&self) -> (u64, &[u8]) {
59        unsigned_varint::decode::u64(&self.0).unwrap()
60    }
61
62    #[inline(always)]
63    pub fn codec(&self) -> u64 {
64        self.parts().0
65    }
66
67    #[inline(always)]
68    pub fn data(&self) -> &[u8] {
69        self.parts().1
70    }
71
72    /// Returns the raw bytes, including the codec prefix.
73    #[inline(always)]
74    pub fn as_bytes(&self) -> &[u8] {
75        &self.0
76    }
77
78    #[inline(always)]
79    pub fn decode<T: MultiCodec>(&self) -> Result<T, Error> {
80        let (codec, bytes) = self.parts();
81        T::from_codec_and_bytes(codec, bytes)
82    }
83}
84
85#[derive(Clone)]
86pub struct MultiEncodedBuf(Vec<u8>);
87
88impl MultiEncodedBuf {
89    /// Creates a new multi-encoded slice from the given `bytes`.
90    ///
91    /// Following the [`unsigned-varint`] specification and to avoid memory
92    /// attacks, the coded must be encoded on at most 9 bytes (63 bits unsigned
93    /// varint).
94    ///
95    /// [`unsigned-varint`](https://github.com/multiformats/unsigned-varint)
96    #[inline(always)]
97    pub fn new(bytes: Vec<u8>) -> Result<Self, Error> {
98        unsigned_varint::decode::u64(&bytes)?;
99        Ok(Self(bytes))
100    }
101
102    pub fn encode_bytes(codec: u64, bytes: &[u8]) -> Self {
103        let mut codec_buffer = [0u8; 10];
104        let encoded_codec = unsigned_varint::encode::u64(codec, &mut codec_buffer);
105        let mut result = Vec::with_capacity(encoded_codec.len() + bytes.len());
106        result.extend(encoded_codec);
107        result.extend(bytes);
108        Self(result)
109    }
110
111    pub fn encode<T: MultiCodec>(value: &T) -> Self {
112        let (codec, bytes) = value.to_codec_and_bytes();
113        Self::encode_bytes(codec, &bytes)
114    }
115
116    /// Creates a new multi-encoded slice from the given `bytes` without
117    /// checking the codec.
118    ///
119    /// # Safety
120    ///
121    /// Following the [`unsigned-varint`] specification and to avoid memory
122    /// attacks, the coded must be encoded on at most 9 bytes (63 bits unsigned
123    /// varint).
124    ///
125    /// [`unsigned-varint`](https://github.com/multiformats/unsigned-varint)
126    #[inline(always)]
127    pub unsafe fn new_unchecked(bytes: Vec<u8>) -> Self {
128        Self(bytes)
129    }
130
131    #[inline(always)]
132    pub fn as_multi_encoded(&self) -> &MultiEncoded {
133        unsafe { MultiEncoded::new_unchecked(&self.0) }
134    }
135
136    /// Returns the raw bytes, including the codec prefix.
137    #[inline(always)]
138    pub fn into_bytes(self) -> Vec<u8> {
139        self.0
140    }
141}
142
143impl Deref for MultiEncodedBuf {
144    type Target = MultiEncoded;
145
146    fn deref(&self) -> &Self::Target {
147        self.as_multi_encoded()
148    }
149}
150
151impl AsRef<[u8]> for MultiEncodedBuf {
152    fn as_ref(&self) -> &[u8] {
153        self.as_bytes()
154    }
155}