use core::{
fmt::{self, Formatter},
str::FromStr,
};
#[derive(Debug)]
pub struct InvalidTagLength;
impl fmt::Display for InvalidTagLength {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("invalid 4CC tag length")
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidTagLength {}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Tag(u32);
impl Tag {
#[inline(always)]
pub const fn from_bytes(bytes: [u8; 4]) -> Self {
Self(u32::from_be_bytes(bytes))
}
#[inline(always)]
pub const fn to_bytes(self) -> [u8; 4] {
self.0.to_be_bytes()
}
}
impl From<[u8; 4]> for Tag {
fn from(value: [u8; 4]) -> Self {
Tag(u32::from_be_bytes(value))
}
}
impl From<Tag> for [u8; 4] {
fn from(value: Tag) -> Self {
value.0.to_be_bytes()
}
}
impl From<u32> for Tag {
fn from(value: u32) -> Self {
Tag(value)
}
}
impl From<Tag> for u32 {
fn from(value: Tag) -> Self {
value.0
}
}
impl<'a> From<&'a [u8; 4]> for Tag {
fn from(value: &'a [u8; 4]) -> Self {
(*value).into()
}
}
impl<'a> TryFrom<&'a [u8]> for Tag {
type Error = InvalidTagLength;
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
let value: &[u8; 4] = value.try_into().map_err(|_| InvalidTagLength)?;
Ok(value.into())
}
}
impl<'a> TryFrom<&'a str> for Tag {
type Error = InvalidTagLength;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
value.as_bytes().try_into()
}
}
impl FromStr for Tag {
type Err = InvalidTagLength;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.as_bytes().try_into()
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.to_bytes().escape_ascii(), f)
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Tag('{}')", self.to_bytes().escape_ascii())
}
}
#[cfg(feature = "serde")]
mod serde {
use super::Tag;
use core::fmt::Formatter;
use serde::{
de::{Error, Visitor},
Deserializer, Serializer,
};
impl serde::Serialize for Tag {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = self.to_bytes();
if bytes.iter().all(u8::is_ascii_graphic) {
serializer.serialize_str(core::str::from_utf8(&bytes).unwrap())
} else {
serializer.serialize_bytes(&bytes)
}
}
}
struct TagVisitor;
impl Visitor<'_> for TagVisitor {
type Value = Tag;
fn expecting(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
formatter.write_str("either a 4-byte string or a 4-byte buffer")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
TryInto::try_into(v).map_err(|_| E::invalid_length(v.len(), &self))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
TryInto::try_into(v).map_err(|_| E::invalid_length(v.len(), &self))
}
}
impl<'de> serde::Deserialize<'de> for Tag {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(TagVisitor)
}
}
}