use super::dta::release::Release;
use super::missing_value::MissingValue;
use super::stata_error::{Result, StataError};
use super::stata_int::StataInt;
use super::stata_long::StataLong;
const DTA_113_MAX_INT8: i8 = 100;
const MISSING_BYTE_SYSTEM_113: u8 = 0x65;
const MISSING_BYTE_SYSTEM_PRE_113: u8 = 0x7F;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StataByte {
Present(i8),
Missing(MissingValue),
}
impl StataByte {
pub fn from_raw(raw: u8, release: Release) -> Result<Self> {
let signed = raw.cast_signed();
if release.supports_tagged_missing() {
if signed > DTA_113_MAX_INT8 {
Ok(Self::Missing(MissingValue::try_from(raw)?))
} else {
Ok(Self::Present(signed))
}
} else if raw == MISSING_BYTE_SYSTEM_PRE_113 {
Ok(Self::Missing(MissingValue::System))
} else {
Ok(Self::Present(signed))
}
}
pub fn to_raw(self, release: Release) -> Result<u8> {
match self {
Self::Present(v) => Ok(v.cast_unsigned()),
Self::Missing(mv) => {
if release.supports_tagged_missing() {
Ok(MISSING_BYTE_SYSTEM_113 + mv.code())
} else if mv == MissingValue::System {
Ok(MISSING_BYTE_SYSTEM_PRE_113)
} else {
Err(StataError::TaggedMissingUnsupported)
}
}
}
}
#[must_use]
#[inline]
pub fn present(self) -> Option<i8> {
match self {
Self::Present(v) => Some(v),
Self::Missing(_) => None,
}
}
}
impl TryFrom<StataInt> for StataByte {
type Error = std::num::TryFromIntError;
fn try_from(value: StataInt) -> std::result::Result<Self, Self::Error> {
match value {
StataInt::Present(v) => Ok(Self::Present(i8::try_from(v)?)),
StataInt::Missing(mv) => Ok(Self::Missing(mv)),
}
}
}
impl TryFrom<StataLong> for StataByte {
type Error = std::num::TryFromIntError;
fn try_from(value: StataLong) -> std::result::Result<Self, Self::Error> {
match value {
StataLong::Present(v) => Ok(Self::Present(i8::try_from(v)?)),
StataLong::Missing(mv) => Ok(Self::Missing(mv)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn v113_present_zero() {
assert_eq!(
StataByte::from_raw(0_u8, Release::V113).unwrap(),
StataByte::Present(0)
);
}
#[test]
fn v113_present_one() {
assert_eq!(
StataByte::from_raw(1_u8, Release::V113).unwrap(),
StataByte::Present(1)
);
}
#[test]
fn v113_present_max() {
assert_eq!(
StataByte::from_raw(100_u8, Release::V113).unwrap(),
StataByte::Present(100)
);
}
#[test]
fn v113_present_min() {
assert_eq!(
StataByte::from_raw(0x81_u8, Release::V113).unwrap(),
StataByte::Present(-127)
);
}
#[test]
fn v113_present_negative_one() {
assert_eq!(
StataByte::from_raw(0xFF_u8, Release::V113).unwrap(),
StataByte::Present(-1)
);
}
#[test]
fn v113_present_negative_128() {
assert_eq!(
StataByte::from_raw(0x80_u8, Release::V113).unwrap(),
StataByte::Present(-128)
);
}
#[test]
fn v113_missing_system() {
assert_eq!(
StataByte::from_raw(0x65_u8, Release::V113).unwrap(),
StataByte::Missing(MissingValue::System),
);
}
#[test]
fn v113_missing_a() {
assert_eq!(
StataByte::from_raw(0x66_u8, Release::V113).unwrap(),
StataByte::Missing(MissingValue::A),
);
}
#[test]
fn v113_missing_z() {
assert_eq!(
StataByte::from_raw(0x7F_u8, Release::V113).unwrap(),
StataByte::Missing(MissingValue::Z),
);
}
#[test]
fn v104_present_zero() {
assert_eq!(
StataByte::from_raw(0_u8, Release::V104).unwrap(),
StataByte::Present(0)
);
}
#[test]
fn v104_present_101_is_data() {
assert_eq!(
StataByte::from_raw(0x65_u8, Release::V104).unwrap(),
StataByte::Present(101),
);
}
#[test]
fn v104_present_126_is_data() {
assert_eq!(
StataByte::from_raw(0x7E_u8, Release::V104).unwrap(),
StataByte::Present(126),
);
}
#[test]
fn v104_present_negative_128() {
assert_eq!(
StataByte::from_raw(0x80_u8, Release::V104).unwrap(),
StataByte::Present(-128),
);
}
#[test]
fn v104_missing_system() {
assert_eq!(
StataByte::from_raw(0x7F_u8, Release::V104).unwrap(),
StataByte::Missing(MissingValue::System),
);
}
#[test]
fn v105_missing_system() {
assert_eq!(
StataByte::from_raw(0x7F_u8, Release::V105).unwrap(),
StataByte::Missing(MissingValue::System),
);
}
#[test]
fn v112_missing_system() {
assert_eq!(
StataByte::from_raw(0x7F_u8, Release::V112).unwrap(),
StataByte::Missing(MissingValue::System),
);
}
#[test]
fn v113_to_raw_present_zero() {
assert_eq!(StataByte::Present(0).to_raw(Release::V113).unwrap(), 0);
}
#[test]
fn v113_to_raw_present_max() {
assert_eq!(StataByte::Present(100).to_raw(Release::V113).unwrap(), 100);
}
#[test]
fn v113_to_raw_present_min() {
assert_eq!(
StataByte::Present(-127).to_raw(Release::V113).unwrap(),
0x81
);
}
#[test]
fn v104_to_raw_present_101() {
assert_eq!(StataByte::Present(101).to_raw(Release::V104).unwrap(), 101);
}
#[test]
fn v113_to_raw_missing_system() {
assert_eq!(
StataByte::Missing(MissingValue::System)
.to_raw(Release::V113)
.unwrap(),
0x65,
);
}
#[test]
fn v104_to_raw_missing_system() {
assert_eq!(
StataByte::Missing(MissingValue::System)
.to_raw(Release::V104)
.unwrap(),
0x7F,
);
}
#[test]
fn v113_to_raw_missing_a() {
assert_eq!(
StataByte::Missing(MissingValue::A)
.to_raw(Release::V113)
.unwrap(),
0x66,
);
}
#[test]
fn v113_to_raw_missing_z() {
assert_eq!(
StataByte::Missing(MissingValue::Z)
.to_raw(Release::V113)
.unwrap(),
0x7F,
);
}
#[test]
fn v104_to_raw_missing_tagged_errors() {
assert_eq!(
StataByte::Missing(MissingValue::A).to_raw(Release::V104),
Err(StataError::TaggedMissingUnsupported),
);
}
#[test]
fn v112_to_raw_missing_tagged_errors() {
assert_eq!(
StataByte::Missing(MissingValue::Z).to_raw(Release::V112),
Err(StataError::TaggedMissingUnsupported),
);
}
#[test]
fn present_returns_inner_for_present() {
assert_eq!(StataByte::Present(42).present(), Some(42));
}
#[test]
fn present_returns_none_for_missing() {
assert_eq!(StataByte::Missing(MissingValue::System).present(), None);
assert_eq!(StataByte::Missing(MissingValue::A).present(), None);
}
#[test]
fn try_from_int_in_range() {
assert_eq!(
StataByte::try_from(StataInt::Present(42)).unwrap(),
StataByte::Present(42),
);
}
#[test]
fn try_from_int_at_i8_max() {
assert_eq!(
StataByte::try_from(StataInt::Present(127)).unwrap(),
StataByte::Present(127),
);
}
#[test]
fn try_from_int_above_i8_max_errors() {
assert!(StataByte::try_from(StataInt::Present(128)).is_err());
}
#[test]
fn try_from_int_below_i8_min_errors() {
assert!(StataByte::try_from(StataInt::Present(-129)).is_err());
}
#[test]
fn try_from_int_missing_translates_directly() {
assert_eq!(
StataByte::try_from(StataInt::Missing(MissingValue::System)).unwrap(),
StataByte::Missing(MissingValue::System),
);
assert_eq!(
StataByte::try_from(StataInt::Missing(MissingValue::Z)).unwrap(),
StataByte::Missing(MissingValue::Z),
);
}
#[test]
fn try_from_long_in_range() {
assert_eq!(
StataByte::try_from(StataLong::Present(-1)).unwrap(),
StataByte::Present(-1),
);
}
#[test]
fn try_from_long_above_i8_max_errors() {
assert!(StataByte::try_from(StataLong::Present(1_000_000)).is_err());
}
#[test]
fn try_from_long_missing_translates_directly() {
assert_eq!(
StataByte::try_from(StataLong::Missing(MissingValue::A)).unwrap(),
StataByte::Missing(MissingValue::A),
);
}
}