use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct FixedOpaque16(pub [u8; 16]);
impl FixedOpaque16 {
pub fn new(data: [u8; 16]) -> Self {
Self(data)
}
pub fn as_bytes(&self) -> &[u8; 16] {
&self.0
}
pub fn to_uuid_string(&self) -> String {
format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3],
self.0[4], self.0[5],
self.0[6], self.0[7],
self.0[8], self.0[9],
self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15]
)
}
}
impl std::fmt::Display for FixedOpaque16 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_uuid_string())
}
}
impl Serialize for FixedOpaque16 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_newtype_struct("FixedOpaque16", &FixedOpaqueBytes(&self.0))
}
}
struct FixedOpaqueBytes<'a>(&'a [u8]);
impl Serialize for FixedOpaqueBytes<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.0)
}
}
impl<'de> Deserialize<'de> for FixedOpaque16 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FixedOpaque16Visitor;
impl<'de> de::Visitor<'de> for FixedOpaque16Visitor {
type Value = FixedOpaque16;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("16 bytes of opaque data")
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
if v.len() >= 16 {
let mut arr = [0u8; 16];
arr.copy_from_slice(&v[..16]);
Ok(FixedOpaque16(arr))
} else {
Err(E::invalid_length(v.len(), &self))
}
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: de::SeqAccess<'de>,
{
let mut arr = [0u8; 16];
for i in 0..16 {
arr[i] = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(i, &self))?;
}
Ok(FixedOpaque16(arr))
}
}
deserializer.deserialize_newtype_struct("FixedOpaque16", FixedOpaque16Visitor)
}
}