use std::fmt::{Display, Formatter};
use bincode_next::{
BorrowDecode, Decode, Encode,
de::{BorrowDecoder, Decoder},
enc::Encoder,
error::{DecodeError, EncodeError},
};
use uuid::Uuid;
#[cfg(test)]
use crate::utils::Mock;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UuidWrapper(Uuid);
impl UuidWrapper {
#[must_use]
pub fn new(uuid: Uuid) -> Self {
Self(uuid)
}
#[must_use]
pub fn as_uuid(&self) -> Uuid {
self.0
}
}
impl Default for UuidWrapper {
fn default() -> Self {
Self(Uuid::new_v4())
}
}
impl From<Uuid> for UuidWrapper {
fn from(uuid: Uuid) -> Self {
Self(uuid)
}
}
impl AsRef<Uuid> for UuidWrapper {
fn as_ref(&self) -> &Uuid {
&self.0
}
}
#[cfg(test)]
impl Mock for UuidWrapper {
fn mock() -> Self {
Self(Uuid::new_v4())
}
}
impl Display for UuidWrapper {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<Context> Decode<Context> for UuidWrapper {
fn decode<D: Decoder<Context = Context>>(decoder: &mut D) -> Result<Self, DecodeError> {
let s = String::decode(decoder)?;
let uuid = Uuid::parse_str(&s).map_err(|e| {
DecodeError::OtherString(format!("failed to parse Uuid from string: {e}"))
})?;
Ok(UuidWrapper(uuid))
}
}
impl<'de, Context> BorrowDecode<'de, Context> for UuidWrapper {
fn borrow_decode<D: BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, DecodeError> {
let s = String::decode(decoder)?;
let uuid = Uuid::parse_str(&s).map_err(|e| {
DecodeError::OtherString(format!("failed to parse Uuid from string: {e}"))
})?;
Ok(UuidWrapper(uuid))
}
}
impl Encode for UuidWrapper {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
let s = format!("{}", self.0);
s.encode(encoder)
}
}
#[cfg(test)]
mod tests {
use bincode_next::{config::standard, decode_from_slice, encode_to_vec};
use uuid::Uuid;
use super::UuidWrapper;
#[test]
fn uuid_wrapper_bincode_round_trip() {
let uuid = Uuid::new_v4();
let wrapper = UuidWrapper::new(uuid);
let encoded = encode_to_vec(wrapper, standard()).unwrap();
let (decoded, _): (UuidWrapper, _) = decode_from_slice(&encoded, standard()).unwrap();
assert_eq!(decoded.as_uuid(), uuid);
}
#[test]
fn uuid_wrapper_display_matches_hyphenated() {
let uuid = Uuid::new_v4();
let wrapper = UuidWrapper::new(uuid);
assert_eq!(format!("{wrapper}"), uuid.to_string());
}
#[test]
fn uuid_wrapper_from_uuid() {
let uuid = Uuid::new_v4();
let wrapper = UuidWrapper::from(uuid);
assert_eq!(wrapper.as_uuid(), uuid);
}
}