caff-archive 0.1.0

a library for manipulating CAFF archives
Documentation
use crate::prelude::*;
use std::ops::{BitXor, BitXorAssign};

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(test, derive(Arbitrary))]
pub struct Key(u32);

impl std::fmt::Debug for Key {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.write_fmt(format_args!("Key({:#010X?})", self.0))
  }
}

impl From<u32> for Key {
  fn from(value: u32) -> Self {
    Self(value)
  }
}

impl Default for Key {
  fn default() -> Self {
    Self::from(0)
  }
}

impl From<Key> for u32 {
  fn from(key: Key) -> Self {
    key.0
  }
}

impl From<Key> for u16 {
  fn from(key: Key) -> Self {
    (key.0 & u32::from(u16::MAX)) as u16
  }
}

impl From<Key> for u8 {
  fn from(key: Key) -> Self {
    (key.0 & u32::from(u8::MAX)) as u8
  }
}

impl<T> BitXor<T> for Key
where
  T: From<Key> + BitXor<T, Output = T>,
{
  type Output = T;
  fn bitxor(self, value: T) -> Self::Output {
    T::from(self) ^ value
  }
}

impl BitXor<Key> for u32 {
  type Output = u32;
  fn bitxor(self, key: Key) -> Self::Output {
    key ^ self
  }
}

impl BitXor<Key> for u16 {
  type Output = u16;
  fn bitxor(self, key: Key) -> Self::Output {
    key ^ self
  }
}

impl BitXor<Key> for u8 {
  type Output = u8;
  fn bitxor(self, key: Key) -> Self::Output {
    key ^ self
  }
}

impl BitXorAssign<Key> for u32 {
  fn bitxor_assign(&mut self, key: Key) {
    self.bitxor_assign(Self::from(key))
  }
}

impl BitXorAssign<Key> for u8 {
  fn bitxor_assign(&mut self, key: Key) {
    self.bitxor_assign(Self::from(key))
  }
}

impl Key {
  pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Self> {
    reader.trace(|reader| {
      let value = reader.read_u32::<BigEndian>()?.into();
      Ok(value)
    })
  }

  pub fn write<W: Write + Seek>(self, writer: &mut W) -> Result<()> {
    writer.trace(|writer| {
      writer.write_u32::<BigEndian>(self.into())?;
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use test_strategy::proptest;

  #[proptest]
  fn roundtrip(expected: Key) {
    let mut buffer = Cursor::new(Vec::new());

    expected.write(&mut buffer).unwrap();
    buffer.rewind().unwrap();
    let actual = Key::read(&mut buffer).unwrap();

    assert_eq!(expected, actual);
  }

  #[proptest]
  fn default(value: u32) {
    let expected = value;
    let actual = Key::default() ^ value;

    assert_eq!(expected, actual)
  }

  mod bitxor {
    use super::*;

    #[proptest]
    fn u32(key: Key, value: u32) {
      let expected = value ^ u32::from(key);
      let actual = value ^ key;

      assert_eq!(expected, actual);
    }

    #[proptest]
    fn u16(key: Key, value: u16) {
      let expected = value ^ u16::from(key);
      let actual = value ^ key;

      assert_eq!(expected, actual);
    }

    #[proptest]
    fn u8(key: Key, value: u8) {
      let expected = value ^ u8::from(key);
      let actual = value ^ key;

      assert_eq!(expected, actual);
    }
  }
}