anonymous_table 0.3.3

A way to store data regardless of type
Documentation
//
//  Testing anonymity
//

#[cfg(test)]
mod anonymous_test{
    use crate::anonymous::{self, Anonymous};

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    struct ComplexStruct{
        one: i32,
        two: ContainsPrimitiveValue
    }
    // this is just for testing purposes, in real use 0 is an invalid id
    impl anonymous::Anonymous for ComplexStruct{ fn id() -> u16 { 0 } }

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    enum Empty{
        One,
        Two
    }
    // this is just for testing purposes, in real use 0 is an invalid id
    impl anonymous::Anonymous for Empty{ fn id() -> u16 { 0 } }

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    enum ContainsPrimitiveValue{
        One(i32),
        Two(i32)
    }
    // this is just for testing purposes, in real use 0 is an invalid id
    impl anonymous::Anonymous for ContainsPrimitiveValue{ fn id() -> u16{ 0 } }

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    enum ContainsComplex{
        One(ComplexStruct),
        Two(ComplexStruct)
    }
    impl anonymous::Anonymous for ContainsComplex{ fn id() -> u16 { 0 } }

    //
    //  Assignments
    //
    #[test]
    fn assign_primitive() {
        let data = 120;
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(data, *unsafe{ cell.get_ref()} );
    }
    #[test]
    fn assign_complex() {
        let data = ComplexStruct{
            one: 1,
            two: ContainsPrimitiveValue::Two(2)
        };
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(data, *unsafe{ cell.get_ref()} );
    }
    #[test]
    fn assign_none_primitive() {
        let data: Option<i32> = None;
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(None, *unsafe{ cell.get_ref::<Option<i32>>()} );
    }
    #[test]
    fn assign_some_primitive() {
        let data: Option<i32> = Some(1);
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(Some(1), *unsafe{ cell.get_ref::<Option<i32>>()} );
    }
    #[test]
    fn assign_empty_enum() {
        let data = Empty::One;
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(Empty::One, *unsafe{ cell.get_ref::<Empty>()} );
        assert_ne!(Empty::Two, *unsafe{ cell.get_ref::<Empty>()} );
    }
    #[test]
    fn assign_primitive_enum() {
        let data = ContainsPrimitiveValue::One(1);
        let cell = anonymous::AnonymousCell::new(data);
        assert_eq!(ContainsPrimitiveValue::One(1), *unsafe{ cell.get_ref::<ContainsPrimitiveValue>()} );
        assert_ne!(ContainsPrimitiveValue::One(2), *unsafe{ cell.get_ref::<ContainsPrimitiveValue>()} );
        assert_ne!(ContainsPrimitiveValue::Two(1), *unsafe{ cell.get_ref::<ContainsPrimitiveValue>()} );
        assert_ne!(ContainsPrimitiveValue::Two(2), *unsafe{ cell.get_ref::<ContainsPrimitiveValue>()} );
    }
    #[test]
    fn assign_complex_enum() {
        let data = ComplexStruct{ one: 1, two: ContainsPrimitiveValue::Two(2) };
        let alternative = ComplexStruct{ one: 2, two: ContainsPrimitiveValue::One(1) };
        let cell = anonymous::AnonymousCell::new(ContainsComplex::One(data));
        assert_eq!(ContainsComplex::One(data), *unsafe{ cell.get_ref() });
        assert_ne!(ContainsComplex::One(alternative), *unsafe{ cell.get_ref() });
        assert_ne!(ContainsComplex::Two(data), *unsafe { cell.get_ref() });
        assert_ne!(ContainsComplex::Two(alternative), *unsafe{ cell.get_ref() });
    }

    //
    //  Updates
    //
    #[test]
    fn reassign() {
        let data = 10;
        let mut cell = anonymous::AnonymousCell::new(data);
        unsafe{
            let old = cell.exchange_value(2);
            assert_eq!(10, old);
        }
        assert_eq!(2, *unsafe{ cell.get_ref() });
    }
    #[test]
    fn update_inplace() {
        let data = ComplexStruct{ one: 1, two: ContainsPrimitiveValue::Two(2) };
        let expected = ComplexStruct{ one: 2, two: ContainsPrimitiveValue::Two(2) };
        let mut cell = anonymous::AnonymousCell::new(data);
        unsafe{
            let ptr = cell.get_mut::<ComplexStruct>();
            ptr.one = 2;
            assert_eq!(*cell.get_ref::<ComplexStruct>(), expected);
            assert_ne!(*cell.get_ref::<ComplexStruct>(), data);
        }
    }
    #[test]
    fn multiple_updates() {
        let initial = ComplexStruct{ one: 1, two: ContainsPrimitiveValue::Two(2) };
        let second = ComplexStruct{ one: 2, two: ContainsPrimitiveValue::Two(2) };
        let third = ComplexStruct{ one: 2, two: ContainsPrimitiveValue::One(1) };
        let mut cell = anonymous::AnonymousCell::new(initial);
        unsafe{
            let ptr = cell.get_mut::<ComplexStruct>();
            assert_eq!(*ptr, initial);
            ptr.one = 2;
            assert_eq!(*ptr, second);
            assert_ne!(*ptr, initial);
            ptr.two = ContainsPrimitiveValue::One(1);
            assert_eq!(*ptr, third);
            assert_ne!(*ptr, second);
        }
    }
    #[test]
    fn evil_things() {
        #[repr(C)]
        #[derive(Copy, Clone, Debug)]
        struct Breakable{ one: i32, two: i32 }
        impl anonymous::Anonymous for Breakable{ fn id() -> u16 { 0 } }

        let data = Breakable{ one: 1, two: 2};
        let cell = anonymous::AnonymousCell::new(data);
        unsafe{
            let ptr = cell.get_ref::<i64>();
            let nums: [i32; 2] = std::mem::transmute(*ptr);
            assert_eq!(nums, [1, 2]);
        }
    }
    #[test]
    fn evil_bad_things() {
        #[repr(C)]
        #[derive(Copy, Clone, Debug)]
        struct Larger([i32; 10]);
        impl Anonymous for Larger{ fn id() -> u16 { 0 }}
        let data = 1;
        let cell = anonymous::AnonymousCell::new(data);
        unsafe{
            // larger than the data allocated
            // should panic
            let ptr = cell.get_ref::<Larger>();
            println!("{:?}", *ptr);
        }
    }
    #[test]
    fn edit_under_scope() {
        let data = 1;
        let mut cell = anonymous::AnonymousCell::new(data);
        unsafe {
            cell.exchange_value(2);
        }
        assert_eq!(*unsafe{ cell.get_ref::<i32>() }, 2);
    }
    #[test]
    fn edit_with_move() {
        let data = 1;
        let mut cell = anonymous::AnonymousCell::new(data);
        let mut change = || { 
            unsafe{ cell.exchange_value(2); }
        };
        change();
        assert_eq!(*unsafe{ cell.get_ref::<i32>() }, 2)
    }
}

//
//  Testing rows
//

#[cfg(test)]
mod row_test{
    use crate::table::AnonymousRow;
    use crate::anonymous::Anonymous;

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    struct ComplexStruct{
        one: i32,
        two: u32
    }
    // this is just for testing purposes, in real use 0 is an invalid id
    impl Anonymous for ComplexStruct{ fn id() -> u16 { 0 } }

    #[test]
    fn push() {
        let mut row = AnonymousRow::new();
        assert_eq!(row.len(), 0);
        row.push(1);
        assert_eq!(row.len(), 1);
        row.push(2.0);
        assert_eq!(row.len(), 2);
        row.push(3u32);
        assert_eq!(row.len(), 3);
    }
    #[test]
    fn get() {
        let mut row = AnonymousRow::new();
        row.push(1);
        row.push(2.0);
        row.push(3u32);

        assert_eq!(1, *unsafe{ row.get_at(0).unwrap_unchecked() });
        assert_eq!(2.0, *unsafe{ row.get_at(1).unwrap_unchecked() });
        assert_eq!(3u32, *unsafe{ row.get_at(2).unwrap_unchecked() });
    }
    #[test]
    fn change() {
        let mut row = AnonymousRow::new();
        row.push(1);
        row.push(2.0);
        row.exchange_at(3, 0).unwrap();
        assert_eq!(3, *unsafe{ row.get_at(0).unwrap_unchecked() } );
        assert_eq!(2.0, *unsafe{ row.get_at(1).unwrap_unchecked() });
    }
    #[test]
    fn update() {
        let mut row = AnonymousRow::new();
        row.push(ComplexStruct{ one: 1, two: 2 });
        row.push(2.0);
        unsafe{
            let ptr: &mut ComplexStruct = row.get_mut_at(0).unwrap_unchecked();
            ptr.one = 2;
            assert_eq!(*row.get_at::<ComplexStruct>(0).unwrap_unchecked(), ComplexStruct{ one: 2, two: 2});
        }
    }
}

//
//   Testing tags
//

#[cfg(test)]
mod tag_test{
    use std::str::FromStr;

    use anonymous_table::{AnonymousRow, AnonymousTable, RowName, Tag};

    #[test]
    fn tag_row() {
        let mut table = AnonymousTable::new();
        let mut row = AnonymousRow::new();
        let tag = Tag::new(1020);
        row.push(1.0f32);
        row.push(99 as u64);
        row.push(String::from_str("words").unwrap());
        table.push_row(AnonymousRow::new().chain_push(2.0).chain_push(30));
        table.register_tagged_row(row, tag);
        table.push_row(AnonymousRow::new().chain_push('a'));
        assert_eq!(table.len(), 3);

        let row = table.get_row(1);
        let row = row.unwrap();
        assert_eq!(row.len(), 3);
        let first_cell: &f32 = row.get_at(0).unwrap();
        let second_cell: &u64 = row.get_at(1).unwrap();
        let third_cell: &String = row.get_at(2).unwrap();
        assert_eq!(*first_cell, 1.0f32);
        assert_eq!(*second_cell, 99u64);
        assert_eq!(*third_cell, String::from_str("words").unwrap());
    }

    #[test]
    fn tag_multiple_rows(){
        let tag = Tag::new(19023);
        let row1 = AnonymousRow::new()
            .chain_push(1.0)
            .chain_push(99u32);
        let row2 = AnonymousRow::new()
            .chain_push('a');
        let mut table = AnonymousTable::new();
        table.register_tagged_row(row1, tag);
        table.register_tagged_row(row2, tag);
        assert_eq!(table.len(), 2);
        table.push_row(AnonymousRow::new());
        assert_eq!(table.len(), 3);
        table.register_tagged_row(AnonymousRow::new(), tag);
        assert_eq!(table.len(), 4);

        let rows = table.get_tagged_rows(tag).expect("Tag went unregistered for tag_multiple_rows test");
        assert_eq!(rows.len(), 3);
        for (i, row) in rows.iter().enumerate(){
            assert_eq!(row.len(), 3 - (i+1));
        }
    }

    #[test]
    fn tag_and_name_row(){
        let tag = Tag::new(12034);
        let name = RowName(284735);
        let row = AnonymousRow::new()
            .chain_push(Some(1))
            .chain_push('a');
        let mut table = AnonymousTable::new()
            .chain_push_row(AnonymousRow::new())
            .chain_push_row(AnonymousRow::new());
        table.register_named_tagged_row(row, tag, name);
        
        let name_ref = table.get_named_row_mut(name).unwrap();
        name_ref.exchange_at::<Option<i32>>(None, 0).expect("Failure to exchange value in tag_and_name_row tesst");

        let tagged_rows = table.get_tagged_rows(tag)
            .expect("missing tagged row in tag_and_name_row test");
        let row_ref = tagged_rows.get(0)
            .expect("Tag value never stored in tag_and_row_test");
        let name_ref = table.get_named_row(name)
            .expect("Name lost in tag_and_row_test");
        // check that they're same pointer
        let row_as_raw: *const AnonymousRow = *row_ref;
        let name_as_raw: *const AnonymousRow = name_ref;
        assert_eq!(row_as_raw, name_as_raw);
        // check value was updated, use unwrap bc it returns Option<Option<i32>>
        assert!(name_ref.get_at::<Option<i32>>(0).unwrap().is_none());
    }

    #[test]
    fn get_from_tagged(){
        let tag = Tag::new(12034);
        let row = AnonymousRow::new()
            .chain_push(Some(12));
        let mut table = AnonymousTable::new();
        table.register_tagged_row(row, tag);
        table.register_tagged_row(AnonymousRow::new().chain_push(1.0), tag);

        let tagged_with_wanted = table.get_from_tagged::<Option<i32>>(tag);
        assert!(tagged_with_wanted.is_some());
        assert_eq!(tagged_with_wanted.unwrap().len(), 1);
    }
}