1use alloc::borrow::Cow;
4use alloc::vec::Vec;
5use core::fmt;
6use core::ops::Deref;
7
8#[derive(Clone, Default)]
35pub struct Octets<'a>(Cow<'a, [u8]>);
36
37impl<'a> Octets<'a> {
38 pub const EMPTY: Self = Self(Cow::Borrowed(&[]));
40
41 pub const fn borrowed(octets: &'a [u8]) -> Self {
43 Self(Cow::Borrowed(octets))
44 }
45
46 pub const fn owned(octets: Vec<u8>) -> Octets<'static> {
48 Octets(Cow::Owned(octets))
49 }
50
51 pub fn as_slice(&self) -> &[u8] {
53 &self.0
54 }
55
56 pub fn is_borrowed(&self) -> bool {
58 matches!(self.0, Cow::Borrowed(_))
59 }
60
61 pub fn as_borrowed(&self) -> Option<&'a [u8]> {
64 match self.0 {
65 Cow::Borrowed(octets) => Some(octets),
66 Cow::Owned(_) => None,
67 }
68 }
69
70 #[doc(alias("to_owned", "owned", "keep"))]
73 pub fn into_owned(self) -> Octets<'static> {
74 Octets(Cow::Owned(self.0.into_owned()))
75 }
76
77 pub fn into_vec(self) -> Vec<u8> {
79 self.0.into_owned()
80 }
81
82 pub fn to_mut(&mut self) -> &mut Vec<u8> {
84 self.0.to_mut()
85 }
86}
87
88impl Deref for Octets<'_> {
89 type Target = [u8];
90
91 fn deref(&self) -> &[u8] {
92 &self.0
93 }
94}
95
96impl AsRef<[u8]> for Octets<'_> {
97 fn as_ref(&self) -> &[u8] {
98 &self.0
99 }
100}
101
102impl<'a> From<&'a [u8]> for Octets<'a> {
103 fn from(octets: &'a [u8]) -> Self {
104 Self(Cow::Borrowed(octets))
105 }
106}
107
108impl<'a, const N: usize> From<&'a [u8; N]> for Octets<'a> {
109 fn from(octets: &'a [u8; N]) -> Self {
110 Self(Cow::Borrowed(octets))
111 }
112}
113
114impl<'a> From<&'a Vec<u8>> for Octets<'a> {
115 fn from(octets: &'a Vec<u8>) -> Self {
116 Self(Cow::Borrowed(octets))
117 }
118}
119
120impl From<Vec<u8>> for Octets<'_> {
121 fn from(octets: Vec<u8>) -> Self {
122 Self(Cow::Owned(octets))
123 }
124}
125
126impl<const N: usize> From<[u8; N]> for Octets<'_> {
127 fn from(octets: [u8; N]) -> Self {
128 Self(Cow::Owned(octets.to_vec()))
129 }
130}
131
132impl<'a> From<Cow<'a, [u8]>> for Octets<'a> {
133 fn from(octets: Cow<'a, [u8]>) -> Self {
134 Self(octets)
135 }
136}
137
138impl<'a> From<Octets<'a>> for Vec<u8> {
139 fn from(octets: Octets<'a>) -> Self {
140 octets.into_vec()
141 }
142}
143
144impl PartialEq for Octets<'_> {
145 fn eq(&self, other: &Self) -> bool {
146 self.as_slice() == other.as_slice()
147 }
148}
149
150impl Eq for Octets<'_> {}
151
152impl PartialOrd for Octets<'_> {
153 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
154 Some(self.cmp(other))
155 }
156}
157
158impl Ord for Octets<'_> {
159 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
160 self.as_slice().cmp(other.as_slice())
161 }
162}
163
164impl core::hash::Hash for Octets<'_> {
165 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
166 self.as_slice().hash(state);
167 }
168}
169
170impl PartialEq<[u8]> for Octets<'_> {
171 fn eq(&self, other: &[u8]) -> bool {
172 self.as_slice() == other
173 }
174}
175
176impl PartialEq<&[u8]> for Octets<'_> {
177 fn eq(&self, other: &&[u8]) -> bool {
178 self.as_slice() == *other
179 }
180}
181
182impl PartialEq<Vec<u8>> for Octets<'_> {
183 fn eq(&self, other: &Vec<u8>) -> bool {
184 self.as_slice() == other.as_slice()
185 }
186}
187
188impl<const N: usize> PartialEq<[u8; N]> for Octets<'_> {
189 fn eq(&self, other: &[u8; N]) -> bool {
190 self.as_slice() == other
191 }
192}
193
194impl PartialEq<Octets<'_>> for [u8] {
195 fn eq(&self, other: &Octets<'_>) -> bool {
196 self == other.as_slice()
197 }
198}
199
200impl PartialEq<Octets<'_>> for Vec<u8> {
201 fn eq(&self, other: &Octets<'_>) -> bool {
202 self.as_slice() == other.as_slice()
203 }
204}
205
206impl crate::AsnType for Octets<'_> {
208 const NAME: &'static str = "OCTET STRING";
209}
210
211impl<'a> crate::Decode<'a> for Octets<'a> {
212 fn decode(reader: &mut crate::Reader<'a>) -> Result<Self, crate::Error> {
213 reader.octet_string(0, crate::UNBOUNDED)
214 }
215}
216
217impl crate::Encode for Octets<'_> {
218 fn encode(&self, writer: &mut crate::Writer<'_>) -> Result<(), crate::Error> {
219 writer.octet_string(self, 0, crate::UNBOUNDED)
220 }
221}
222
223#[cfg(feature = "inspect")]
224impl crate::json::Tree for Octets<'_> {
225 const NAME: &'static str = "OCTET STRING";
226
227 fn to_tree(&self) -> crate::json::Value {
228 crate::json::octets(self)
229 }
230
231 fn from_tree(
232 value: &crate::json::Value,
233 reading: &mut crate::json::Reading,
234 ) -> Result<Self, crate::json::Refused> {
235 crate::json::read_octets(reading, value)
236 }
237}
238
239impl fmt::Debug for Octets<'_> {
241 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
242 write_hex(self.as_slice(), formatter)
243 }
244}
245
246pub(crate) fn write_hex(octets: &[u8], formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
248 for octet in octets {
249 write!(formatter, "{octet:02x}")?;
250 }
251 Ok(())
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257 use alloc::format;
258 use alloc::vec;
259
260 #[test]
261 fn octets_are_borrowed_or_owned_and_compare_by_what_they_hold() {
262 let received = vec![1u8, 2, 3];
263 let borrowed = Octets::from(&received);
264 assert!(borrowed.is_borrowed());
265 let owned = Octets::from(vec![1u8, 2, 3]);
266 assert!(!owned.is_borrowed());
267 assert_eq!(borrowed, owned);
268 assert_eq!(borrowed, [1, 2, 3]);
269 assert_eq!(borrowed, vec![1, 2, 3]);
270 assert_eq!(borrowed, &[1u8, 2, 3][..]);
271 assert_eq!(received, borrowed);
272 let (less, more) = (Octets::from([1u8, 2]), Octets::from([1u8, 3]));
273 assert!(less < more);
274 assert_eq!(Octets::EMPTY.len(), 0);
275 assert_eq!(Octets::default(), Octets::EMPTY);
276
277 let kept: Octets<'static> = borrowed.clone().into_owned();
278 assert!(!kept.is_borrowed());
279 assert_eq!(kept.clone().into_vec(), [1, 2, 3]);
280 assert_eq!(Vec::from(kept), [1, 2, 3]);
281
282 let mut changed = borrowed;
283 changed.to_mut().push(4);
284 assert_eq!(changed, [1, 2, 3, 4]);
285 assert_eq!(format!("{changed:?}"), "01020304");
286 }
287}