use crate::{
HexSlice, ParseHexError, hex_array::decode_hex_into, hex_slice::HexDisplay,
};
use alloc::{borrow::ToOwned, vec, vec::Vec};
use core::{borrow::Borrow, fmt, str::FromStr};
#[must_use]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct HexVec(pub Vec<u8>);
impl HexVec {
#[inline]
pub fn new(bytes: Vec<u8>) -> Self {
Self(bytes)
}
#[inline]
#[must_use]
pub fn into_inner(self) -> Vec<u8> {
self.0
}
#[inline]
fn as_hex_slice(&self) -> &HexSlice {
HexSlice::new(&self.0)
}
}
impl FromStr for HexVec {
type Err = ParseHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if !s.len().is_multiple_of(2) {
return Err(ParseHexError::OddLength { actual: s.len() });
}
let mut out = vec![0u8; s.len() / 2];
decode_hex_into(s, &mut out)?;
Ok(Self(out))
}
}
impl fmt::Debug for HexVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("HexVec").field(&HexDisplay(&self.0)).finish()
}
}
impl fmt::Display for HexVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_hex_slice(), f)
}
}
impl fmt::LowerHex for HexVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(self.as_hex_slice(), f)
}
}
impl fmt::UpperHex for HexVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self.as_hex_slice(), f)
}
}
impl core::ops::Deref for HexVec {
type Target = HexSlice;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_hex_slice()
}
}
impl Borrow<HexSlice> for HexVec {
#[inline]
fn borrow(&self) -> &HexSlice {
self.as_hex_slice()
}
}
impl ToOwned for HexSlice {
type Owned = HexVec;
#[inline]
fn to_owned(&self) -> Self::Owned {
HexVec(self.as_bytes().to_vec())
}
}
impl AsRef<HexSlice> for HexVec {
#[inline]
fn as_ref(&self) -> &HexSlice {
self.as_hex_slice()
}
}
impl AsRef<[u8]> for HexVec {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsMut<[u8]> for HexVec {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl From<Vec<u8>> for HexVec {
#[inline]
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}
impl From<HexVec> for Vec<u8> {
#[inline]
fn from(hex_vec: HexVec) -> Self {
hex_vec.0
}
}
impl PartialEq<HexSlice> for HexVec {
#[inline]
fn eq(&self, other: &HexSlice) -> bool {
self.as_hex_slice() == other
}
}
impl PartialEq<&HexSlice> for HexVec {
#[inline]
fn eq(&self, other: &&HexSlice) -> bool {
self.as_hex_slice() == *other
}
}
impl PartialEq<HexVec> for HexSlice {
#[inline]
fn eq(&self, other: &HexVec) -> bool {
self == other.as_hex_slice()
}
}
impl PartialEq<HexVec> for &HexSlice {
#[inline]
fn eq(&self, other: &HexVec) -> bool {
*self == other.as_hex_slice()
}
}
#[cfg(feature = "serde")]
mod serde_impls {
use super::HexVec;
use crate::HexSlice;
use alloc::vec::Vec;
use core::fmt;
use serde_core::{Deserializer, Serialize, Serializer, de::Visitor};
fn deserialize_hex_vec<'de, D>(deserializer: D) -> Result<HexVec, D::Error>
where
D: Deserializer<'de>,
{
use serde_core::de::Error;
if deserializer.is_human_readable() {
struct HexVecVisitor;
impl<'de2> Visitor<'de2> for HexVecVisitor {
type Value = HexVec;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "a hex string with an even number of hex digits")
}
fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
where
E: Error,
{
data.parse().map_err(Error::custom)
}
}
deserializer.deserialize_str(HexVecVisitor)
} else {
crate::serde_util::deserialize_byte_buf(deserializer).map(HexVec)
}
}
impl HexVec {
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
pub fn serialize<S>(
bytes: &[u8],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
HexSlice::new(bytes).serialize(serializer)
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserialize_hex_vec(deserializer).map(HexVec::into_inner)
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
impl serde_core::Serialize for HexVec {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_hex_slice().serialize(serializer)
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
impl<'de> serde_core::Deserialize<'de> for HexVec {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserialize_hex_vec(deserializer)
}
}
}
#[cfg(feature = "schemars08")]
mod schemars_impls {
use super::HexVec;
use crate::{HexSlice, schemars_util::x_rust_type_extension};
use alloc::{boxed::Box, string::String};
use schemars08::{
JsonSchema,
r#gen::SchemaGenerator,
schema::{InstanceType, Schema, SchemaObject, StringValidation},
};
impl JsonSchema for HexVec {
fn schema_name() -> String {
"HexVec".into()
}
fn is_referenceable() -> bool {
false
}
fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
Schema::Object(SchemaObject {
instance_type: Some(InstanceType::String.into()),
string: Some(Box::new(StringValidation {
pattern: Some("^([0-9a-fA-F]{2})*$".into()),
..Default::default()
})),
extensions: x_rust_type_extension("HexVec"),
..Default::default()
})
}
}
impl JsonSchema for HexSlice {
fn schema_name() -> String {
HexVec::schema_name()
}
fn is_referenceable() -> bool {
HexVec::is_referenceable()
}
fn json_schema(generator: &mut SchemaGenerator) -> Schema {
HexVec::json_schema(generator)
}
}
}