#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum ProfileId {
Generic = 0,
Core = 1,
Hot = 2,
Full = 3,
}
impl TryFrom<u8> for ProfileId {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Generic),
1 => Ok(Self::Core),
2 => Ok(Self::Hot),
3 => Ok(Self::Full),
other => Err(other),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum DomainProfile {
Generic = 0,
Rvdna = 1,
RvText = 2,
RvGraph = 3,
RvVision = 4,
}
impl DomainProfile {
pub const fn magic(self) -> u32 {
match self {
Self::Generic => 0x0000_0000,
Self::Rvdna => 0x5244_4E41, Self::RvText => 0x5254_5854, Self::RvGraph => 0x5247_5248, Self::RvVision => 0x5256_4953, }
}
}
impl DomainProfile {
pub const fn extension(&self) -> &'static str {
match self {
Self::Generic => "rvf",
Self::Rvdna => "rvdna",
Self::RvText => "rvtext",
Self::RvGraph => "rvgraph",
Self::RvVision => "rvvis",
}
}
pub fn from_extension(ext: &str) -> Option<Self> {
let ext_bytes = ext.as_bytes();
if eq_ignore_ascii_case(ext_bytes, b"rvf") {
Some(Self::Generic)
} else if eq_ignore_ascii_case(ext_bytes, b"rvdna") {
Some(Self::Rvdna)
} else if eq_ignore_ascii_case(ext_bytes, b"rvtext") {
Some(Self::RvText)
} else if eq_ignore_ascii_case(ext_bytes, b"rvgraph") {
Some(Self::RvGraph)
} else if eq_ignore_ascii_case(ext_bytes, b"rvvis") {
Some(Self::RvVision)
} else {
None
}
}
}
fn eq_ignore_ascii_case(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
a.iter()
.zip(b.iter())
.all(|(x, y)| x.eq_ignore_ascii_case(y))
}
impl TryFrom<u8> for DomainProfile {
type Error = u8;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Generic),
1 => Ok(Self::Rvdna),
2 => Ok(Self::RvText),
3 => Ok(Self::RvGraph),
4 => Ok(Self::RvVision),
other => Err(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn profile_id_round_trip() {
for raw in 0..=3u8 {
let p = ProfileId::try_from(raw).unwrap();
assert_eq!(p as u8, raw);
}
assert_eq!(ProfileId::try_from(4), Err(4));
}
#[test]
fn domain_profile_round_trip() {
for raw in 0..=4u8 {
let d = DomainProfile::try_from(raw).unwrap();
assert_eq!(d as u8, raw);
}
assert_eq!(DomainProfile::try_from(5), Err(5));
}
#[test]
fn domain_extension_round_trip() {
let profiles = [
DomainProfile::Generic,
DomainProfile::Rvdna,
DomainProfile::RvText,
DomainProfile::RvGraph,
DomainProfile::RvVision,
];
for p in profiles {
let ext = p.extension();
let back = DomainProfile::from_extension(ext).unwrap();
assert_eq!(back, p, "round-trip failed for {ext}");
}
}
#[test]
fn domain_extension_case_insensitive() {
assert_eq!(
DomainProfile::from_extension("RVDNA"),
Some(DomainProfile::Rvdna)
);
assert_eq!(
DomainProfile::from_extension("RvF"),
Some(DomainProfile::Generic)
);
assert_eq!(
DomainProfile::from_extension("RvText"),
Some(DomainProfile::RvText)
);
}
#[test]
fn domain_extension_unknown() {
assert_eq!(DomainProfile::from_extension("txt"), None);
assert_eq!(DomainProfile::from_extension(""), None);
}
#[test]
fn domain_magic_values() {
assert_eq!(&DomainProfile::Rvdna.magic().to_be_bytes(), b"RDNA");
assert_eq!(&DomainProfile::RvText.magic().to_be_bytes(), b"RTXT");
assert_eq!(&DomainProfile::RvGraph.magic().to_be_bytes(), b"RGRH");
assert_eq!(&DomainProfile::RvVision.magic().to_be_bytes(), b"RVIS");
}
}