use avr_oxide::io::{IoError, Read, Write};
use avr_oxide::alloc::vec::Vec;
pub mod derive {
pub use oxide_macros::Persist;
}
pub enum PersistenceError {
SerialisationFailed,
DeserialisationFailed,
IoError
}
pub type PersistenceResult<T> = Result<T,PersistenceError>;
pub trait Persist : Sized {
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self>;
fn load_from_or_default<R: Read>(reader: &mut R) -> Self where Self: Default {
match Self::load_from(reader) {
Ok(me) => me,
Err(_e) => Self::default()
}
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()>;
fn load_with<R: Read>(mut reader: R) -> PersistenceResult<Self> {
Self::load_from(&mut reader)
}
fn load_with_or_default<R: Read>(mut reader: R) -> Self where Self: Default {
Self::load_from_or_default(&mut reader)
}
fn save_with<W: Write>(&self, mut writer: W) -> PersistenceResult<()> {
self.save_to(&mut writer)
}
}
impl From<IoError> for PersistenceError {
fn from(_: IoError) -> Self {
PersistenceError::IoError
}
}
impl Persist for u8 {
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let mut buf : [u8; 1] = [ 0 ];
reader.read(&mut buf)?;
Ok(buf[0])
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
let buf: [u8; 1] = [*self];
match writer.write(&buf) {
Ok(1) => {
Ok(())
},
Ok(_) => {
Err(PersistenceError::IoError)
},
Err(e) => Err(e.into())
}
}
}
impl<T, const WIDTH: usize> Persist for [T; WIDTH]
where
T: Persist
{
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let mut array : [core::mem::MaybeUninit<T>; WIDTH] = core::mem::MaybeUninit::uninit_array();
for element in &mut array {
element.write(T::load_from(reader)?);
}
Ok(unsafe { core::mem::MaybeUninit::array_assume_init(array) })
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
for item in self {
item.save_to(writer)?;
}
Ok(())
}
}
impl Persist for u16 {
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let buf : [u8;2] = Persist::load_from(reader)?;
Ok((buf[0] as u16) << 8 | (buf[1] as u16))
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
let buf = [
((self >> 8) & 0xff) as u8,
((self >> 0) & 0xff) as u8 ];
buf.save_to(writer)
}
}
impl Persist for usize {
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let val:u16 = Persist::load_from(reader)?;
Ok(val as usize)
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
(*self as u16).save_to(writer)
}
}
impl Persist for u32 {
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let buf : [u8;4] = Persist::load_from(reader)?;
Ok((buf[0] as u32) << 24 | (buf[1] as u32) << 16 | (buf[2] as u32) << 8 | (buf[3] as u32))
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
let buf = [
((self >> 24) & 0xff) as u8,
((self >> 16) & 0xff) as u8,
((self >> 8) & 0xff) as u8,
((self >> 0) & 0xff) as u8 ];
buf.save_to(writer)
}
}
impl<T> Persist for Vec<T>
where
T: Persist
{
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let tag:u8 = Persist::load_from(reader)?;
if tag != b'V' {
return Err(PersistenceError::DeserialisationFailed);
}
let count:usize = Persist::load_from(reader)?;
let mut vector : Vec<T> = Vec::with_capacity(count);
for _i in 0..count {
vector.push(Persist::load_from(reader)?)
}
Ok(vector)
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
b'V'.save_to(writer)?;
self.len().save_to(writer)?;
for element in self {
(*element).save_to(writer)?;
}
Ok(())
}
}
impl<T> Persist for Option<T>
where
T: Persist
{
fn load_from<R: Read>(reader: &mut R) -> PersistenceResult<Self> {
let tag:u8 = Persist::load_from(reader)?;
match tag {
b'N' => Ok(Self::None),
b'S' => Ok(Some(T::load_from(reader)?)),
_ => Err(PersistenceError::DeserialisationFailed)
}
}
fn save_to<W: Write>(&self, writer: &mut W) -> PersistenceResult<()> {
match self {
None => {
b'N'.save_to(writer)?;
},
Some(value) => {
b'S'.save_to(writer)?;
value.save_to(writer)?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;
#[test]
fn a_test() {
}
#[test]
#[should_panic]
fn a_failure_test() {
panic!()
}
}