use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Tag(u8);
impl Tag {
pub const ALTVAL: Self = Self(b'A');
pub const SUPVAL: Self = Self(b'S');
pub const HASH: Self = Self(b'H');
pub(crate) const BLOB: Self = Self(b'B');
#[inline]
#[must_use]
pub const fn new(tag: u8) -> Self {
Self(tag)
}
#[inline]
#[must_use]
pub const fn get(self) -> u8 {
self.0
}
#[inline]
pub(crate) const fn raw(self) -> u32 {
self.0 as u32
}
}
impl std::fmt::Debug for Tag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Tag({:?})", self.0 as char)
}
}
#[cfg(test)]
mod tests {
use assert2::assert;
use super::Tag;
#[test]
fn orders_by_raw_byte() {
assert!(Tag::ALTVAL < Tag::HASH);
assert!(Tag::HASH < Tag::SUPVAL);
assert!(Tag::new(b'A') == Tag::ALTVAL);
}
#[test]
fn debug_renders_the_selector_char() {
assert!(format!("{:?}", Tag::ALTVAL) == "Tag('A')");
}
#[test]
fn serde_round_trips() {
let json = serde_json::to_string(&Tag::new(b'X')).unwrap();
assert!(serde_json::from_str::<Tag>(&json).unwrap() == Tag::new(b'X'));
}
mod proptests {
use proptest::prelude::*;
use super::*;
proptest! {
#[test]
fn new_get_and_raw_round_trip(byte in any::<u8>()) {
let tag = Tag::new(byte);
prop_assert_eq!(tag.get(), byte);
prop_assert_eq!(tag.raw(), u32::from(byte));
}
#[test]
fn ord_follows_the_raw_byte(a in any::<u8>(), b in any::<u8>()) {
prop_assert_eq!(Tag::new(a).cmp(&Tag::new(b)), a.cmp(&b));
}
}
}
}