fernfs 0.1.5

A Rust NFS Server implementation
Documentation
use std::fmt::Debug;

use fernfs::xdr::{deserialize, Deserialize, Serialize};

#[derive(Default)]
struct Context {
    buf: Vec<u8>,
}

trait TestValue: Deserialize + Serialize + Eq + Default + Debug + Clone {}
impl<T: Deserialize + Serialize + Eq + Default + Debug + Clone> TestValue for T {}

impl Context {
    fn check<T: TestValue>(&mut self, src_value: &T) {
        for capacity in 0..32 {
            for exsist in 0..capacity {
                self.buf = Vec::with_capacity(capacity);
                self.buf.resize(exsist, Default::default());

                src_value.serialize(&mut self.buf).expect("cannot serialize");
                assert_eq!((self.buf.len() - exsist) % 4, 0);

                let result_value =
                    deserialize::<T>(&mut &self.buf[exsist..]).expect("cannot deserialize");

                assert_eq!(src_value, &result_value);
            }
        }
    }

    fn check_multi<T: TestValue>(&mut self, src_values: &[T]) {
        src_values.iter().for_each(|i| self.check(i));
    }
}

#[derive(Default, PartialEq, Eq, Debug, Clone)]
struct TestForVecU8(Vec<u8>);

impl Serialize for TestForVecU8 {
    fn serialize<W: std::io::Write>(&self, dest: &mut W) -> std::io::Result<()> {
        self.0.serialize(dest)
    }
}

impl Deserialize for TestForVecU8 {
    fn deserialize<R: std::io::Read>(&mut self, src: &mut R) -> std::io::Result<()> {
        self.0.deserialize(src)
    }
}

#[derive(Default, PartialEq, Eq, Debug, Clone)]
struct TestForVec<T>(Vec<T>);

impl<T: TestValue> Serialize for TestForVec<T> {
    fn serialize<W: std::io::Write>(&self, dest: &mut W) -> std::io::Result<()> {
        self.0.serialize(dest)
    }
}

impl<T: TestValue> Deserialize for TestForVec<T> {
    fn deserialize<R: std::io::Read>(&mut self, src: &mut R) -> std::io::Result<()> {
        self.0.deserialize(src)
    }
}

#[derive(Default, PartialEq, Eq, Debug, Clone)]
struct TestForString(String);

impl Serialize for TestForString {
    fn serialize<W: std::io::Write>(&self, dest: &mut W) -> std::io::Result<()> {
        self.0.serialize(dest)
    }
}

impl Deserialize for TestForString {
    fn deserialize<R: std::io::Read>(&mut self, src: &mut R) -> std::io::Result<()> {
        self.0.deserialize(src)
    }
}

#[test]
fn test_scalar_bijection() {
    let mut ctx = Context::default();

    ctx.check_multi(&[true, false]);

    ctx.check_multi(&[i32::MIN, -1i32, 0i32, 1i32, i32::MAX]);
    ctx.check_multi(&[i64::MIN, -1i64, 0i64, 1i64, i64::MAX]);

    ctx.check_multi(&[u32::MIN, 0u32, 1u32, 2u32, u32::MAX]);
    ctx.check_multi(&[u64::MIN, 0u64, 1u64, 2u64, u64::MAX]);
}

#[test]
fn test_array_bijection() {
    let mut ctx = Context::default();

    ctx.check(&[1u8]);
    ctx.check(&[1u8, 2u8, 3u8]);
    ctx.check(&[1u8, 2u8, 3u8, 4u8, 5u8, 6u8]);

    ctx.check(&[0u32]);
    ctx.check(&[1u32, 2u32, 3u32]);
    ctx.check(&[1u64, 2u64, 3u64]);
    ctx.check(&[1u64, 2u64, 3u64, 4u64]);
    ctx.check(&[1u64, 2u64, 3u64, 4u64, 5u64]);
}

#[test]
fn test_str_bijection() {
    let mut ctx = Context::default();

    ctx.check_multi(&[
        TestForString(String::from("")),
        TestForString(String::from("abc1234+-")),
        TestForString(String::from("abc")),
    ]);
}

#[test]
fn test_vec_bijection() {
    let mut ctx = Context::default();

    ctx.check_multi(&[
        TestForVecU8(vec![]),
        TestForVecU8(vec![1u8]),
        TestForVecU8(vec![1u8, 2u8, 3u8]),
        TestForVecU8(vec![1u8, 2u8, 3u8, 4u8]),
    ]);
    ctx.check_multi(&[
        TestForVec(vec![]),
        TestForVec(vec![1u32]),
        TestForVec(vec![1u32, 2u32, 3u32]),
        TestForVec(vec![1u32, 2u32, 3u32, 4u32]),
    ]);
    ctx.check_multi(&[
        TestForVec(vec![]),
        TestForVec(vec![1u64]),
        TestForVec(vec![1u64, 2u64, 3u64]),
        TestForVec(vec![1u64, 2u64, 3u64, 4u64]),
    ]);
}

#[cfg(test)]
mod portmap {
    use fernfs::xdr::portmap::{mapping, pmaplist};
    use fernfs::xdr::{deserialize, Serialize};
    use num_traits::Zero;
    use std::io::Cursor;

    const VERSION: u32 = 2;
    const TCP: u32 = 6;

    fn generate_list(numb: u32, amount: u32) -> Option<pmaplist> {
        match amount.is_zero() {
            true => None,
            false => {
                let map = mapping { prog: numb, vers: VERSION, prot: TCP, port: numb };
                if numb < amount {
                    Some(pmaplist { map, next: Box::new(generate_list(numb + 1, amount)) })
                } else {
                    Some(pmaplist { map, next: Box::from(None) })
                }
            }
        }
    }

    fn test_pmaplist(amount: u32) {
        let mut pmaplist = &generate_list(0, amount);
        let mut buffer = Cursor::new(Vec::with_capacity((4 * (2 * amount + 1)) as usize));
        pmaplist.serialize(&mut buffer).expect("can't serialize pmaplist");
        buffer.set_position(0);
        let mut result = &deserialize::<Option<pmaplist>>(&mut buffer).unwrap();
        while let (Some(pmap_node), Some(result_node)) = (pmaplist, result) {
            assert!(
                pmap_node.map.prog == result_node.map.prog
                    && pmap_node.map.vers == result_node.map.vers
                    && pmap_node.map.prot == result_node.map.prot
                    && pmap_node.map.port == result_node.map.port
            );
            pmaplist = &pmap_node.next;
            result = &result_node.next;
        }
        assert!(pmaplist.is_none() && result.is_none())
    }

    #[test]
    fn pmaplist_tests() {
        test_pmaplist(0);
        test_pmaplist(1);
        test_pmaplist(5);
        test_pmaplist(458);
    }
}