1use crate::{
7 HexSlice, ParseHexError, hex_array::decode_hex_into, hex_slice::HexDisplay,
8};
9use alloc::{borrow::ToOwned, vec, vec::Vec};
10use core::{borrow::Borrow, fmt, str::FromStr};
11
12#[must_use]
36#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
37pub struct HexVec(pub Vec<u8>);
38
39impl HexVec {
40 #[inline]
42 pub fn new(bytes: Vec<u8>) -> Self {
43 Self(bytes)
44 }
45
46 #[inline]
48 #[must_use]
49 pub fn into_inner(self) -> Vec<u8> {
50 self.0
51 }
52
53 #[inline]
54 fn as_hex_slice(&self) -> &HexSlice {
55 HexSlice::new(&self.0)
56 }
57}
58
59impl FromStr for HexVec {
60 type Err = ParseHexError;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 if !s.len().is_multiple_of(2) {
64 return Err(ParseHexError::OddLength { actual: s.len() });
65 }
66 let mut out = vec![0u8; s.len() / 2];
67 decode_hex_into(s, &mut out)?;
68 Ok(Self(out))
69 }
70}
71
72impl fmt::Debug for HexVec {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.debug_tuple("HexVec").field(&HexDisplay(&self.0)).finish()
75 }
76}
77
78impl fmt::Display for HexVec {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 fmt::Display::fmt(self.as_hex_slice(), f)
81 }
82}
83
84impl fmt::LowerHex for HexVec {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 fmt::LowerHex::fmt(self.as_hex_slice(), f)
87 }
88}
89
90impl fmt::UpperHex for HexVec {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 fmt::UpperHex::fmt(self.as_hex_slice(), f)
93 }
94}
95
96impl core::ops::Deref for HexVec {
97 type Target = HexSlice;
98
99 #[inline]
100 fn deref(&self) -> &Self::Target {
101 self.as_hex_slice()
102 }
103}
104
105impl Borrow<HexSlice> for HexVec {
106 #[inline]
107 fn borrow(&self) -> &HexSlice {
108 self.as_hex_slice()
109 }
110}
111
112impl ToOwned for HexSlice {
113 type Owned = HexVec;
114
115 #[inline]
116 fn to_owned(&self) -> Self::Owned {
117 HexVec(self.as_bytes().to_vec())
118 }
119}
120
121impl AsRef<HexSlice> for HexVec {
122 #[inline]
123 fn as_ref(&self) -> &HexSlice {
124 self.as_hex_slice()
125 }
126}
127
128impl AsRef<[u8]> for HexVec {
129 #[inline]
130 fn as_ref(&self) -> &[u8] {
131 &self.0
132 }
133}
134
135impl AsMut<[u8]> for HexVec {
136 #[inline]
137 fn as_mut(&mut self) -> &mut [u8] {
138 &mut self.0
139 }
140}
141
142impl From<Vec<u8>> for HexVec {
143 #[inline]
144 fn from(bytes: Vec<u8>) -> Self {
145 Self(bytes)
146 }
147}
148
149impl From<HexVec> for Vec<u8> {
150 #[inline]
151 fn from(hex_vec: HexVec) -> Self {
152 hex_vec.0
153 }
154}
155
156impl PartialEq<HexSlice> for HexVec {
157 #[inline]
158 fn eq(&self, other: &HexSlice) -> bool {
159 self.as_hex_slice() == other
160 }
161}
162
163impl PartialEq<&HexSlice> for HexVec {
164 #[inline]
165 fn eq(&self, other: &&HexSlice) -> bool {
166 self.as_hex_slice() == *other
167 }
168}
169
170impl PartialEq<HexVec> for HexSlice {
171 #[inline]
172 fn eq(&self, other: &HexVec) -> bool {
173 self == other.as_hex_slice()
174 }
175}
176
177impl PartialEq<HexVec> for &HexSlice {
178 #[inline]
179 fn eq(&self, other: &HexVec) -> bool {
180 *self == other.as_hex_slice()
181 }
182}
183
184#[cfg(feature = "serde")]
185mod serde_impls {
186 use super::HexVec;
187 use crate::HexSlice;
188 use alloc::vec::Vec;
189 use core::fmt;
190 use serde_core::{Deserializer, Serialize, Serializer, de::Visitor};
191
192 fn deserialize_hex_vec<'de, D>(deserializer: D) -> Result<HexVec, D::Error>
193 where
194 D: Deserializer<'de>,
195 {
196 use serde_core::de::Error;
197
198 if deserializer.is_human_readable() {
199 struct HexVecVisitor;
200
201 impl<'de2> Visitor<'de2> for HexVecVisitor {
202 type Value = HexVec;
203
204 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 write!(f, "a hex string with an even number of hex digits")
206 }
207
208 fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
209 where
210 E: Error,
211 {
212 data.parse().map_err(Error::custom)
213 }
214 }
215
216 deserializer.deserialize_str(HexVecVisitor)
217 } else {
218 crate::serde_util::deserialize_byte_buf(deserializer).map(HexVec)
219 }
220 }
221
222 impl HexVec {
223 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
245 pub fn serialize<S>(
246 bytes: &[u8],
247 serializer: S,
248 ) -> Result<S::Ok, S::Error>
249 where
250 S: Serializer,
251 {
252 HexSlice::new(bytes).serialize(serializer)
253 }
254
255 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
276 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
277 where
278 D: Deserializer<'de>,
279 {
280 deserialize_hex_vec(deserializer).map(HexVec::into_inner)
281 }
282 }
283
284 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
285 impl serde_core::Serialize for HexVec {
286 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
287 where
288 S: Serializer,
289 {
290 self.as_hex_slice().serialize(serializer)
291 }
292 }
293
294 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
295 impl<'de> serde_core::Deserialize<'de> for HexVec {
296 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
297 where
298 D: Deserializer<'de>,
299 {
300 deserialize_hex_vec(deserializer)
301 }
302 }
303}
304
305#[cfg(feature = "schemars08")]
306mod schemars_impls {
307 use super::HexVec;
308 use crate::{HexSlice, schemars_util::x_rust_type_extension};
309 use alloc::{boxed::Box, string::String};
310 use schemars08::{
311 JsonSchema,
312 r#gen::SchemaGenerator,
313 schema::{InstanceType, Schema, SchemaObject, StringValidation},
314 };
315
316 impl JsonSchema for HexVec {
317 fn schema_name() -> String {
318 "HexVec".into()
319 }
320
321 fn is_referenceable() -> bool {
322 false
323 }
324
325 fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
326 Schema::Object(SchemaObject {
327 instance_type: Some(InstanceType::String.into()),
328 string: Some(Box::new(StringValidation {
329 pattern: Some("^([0-9a-fA-F]{2})*$".into()),
330 ..Default::default()
331 })),
332 extensions: x_rust_type_extension("HexVec"),
333 ..Default::default()
334 })
335 }
336 }
337
338 impl JsonSchema for HexSlice {
342 fn schema_name() -> String {
343 HexVec::schema_name()
344 }
345
346 fn is_referenceable() -> bool {
347 HexVec::is_referenceable()
348 }
349
350 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
351 HexVec::json_schema(generator)
352 }
353 }
354}