multi-array-list 0.2.1

A `MultiArrayList` stores a list of a struct.
Documentation
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

use multi_array_list::MultiArrayList;

#[derive(Clone, PartialEq, Eq, Debug)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct Pizza {
    radius: i32,
    toppings: Vec<Topping>,
}

#[derive(Clone, PartialEq, Eq, Debug)]
#[repr(u8)]
enum Topping {
    Tomato,
    Mozzarella,
    Anchovies,
}

#[test]
fn simple_type() {
    let mut points = MultiArrayList::<Point>::new();
    assert_eq!(0, points.len());

    let point = Point { x: 47, y: 23 };
    points.push(point.clone());
    assert_eq!(1, points.len());
    assert_eq!(Some(&point), points.pop().as_deref());

    assert_eq!(None, points.pop());
    assert_eq!(None, points.pop());
}

#[test]
fn monster() {
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    struct Monster {
        anim: Animation,
        kind: Kind,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    struct Animation {
        x: i32,
        y: i32,
    }

    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    #[repr(u8)]
    enum Kind {
        Snake,
        Wolf,
    }

    let mut monsters = MultiArrayList::<Monster>::new();

    let m1 = Monster {
        anim: Animation { x: 3, y: 2 },
        kind: Kind::Wolf,
    };
    monsters.push(m1);
    assert_eq!(1, monsters.len());
    assert_eq!(1, monsters.capacity());

    let m2 = Monster {
        anim: Animation { x: 17, y: 98 },
        kind: Kind::Snake,
    };
    monsters.push(m2);
    assert_eq!(2, monsters.len());
    assert_eq!(2, monsters.capacity());

    let m = monsters.pop();
    assert_eq!(Some(&m2), m.as_deref());
    assert_eq!(1, monsters.len());
    assert_eq!(2, monsters.capacity());

    monsters.shrink_to_fit();
    assert_eq!(1, monsters.len());
    assert_eq!(1, monsters.capacity());

    let m = monsters.pop();
    assert_eq!(Some(&m1), m.as_deref());
    assert_eq!(0, monsters.len());
    assert_eq!(1, monsters.capacity());

    let m = monsters.pop();
    assert_eq!(None, m);
    assert_eq!(1, monsters.capacity());
}

#[test]
fn nested() {
    let mut order = MultiArrayList::<Pizza>::new();
    assert_eq!(0, order.len());

    let margherita = Pizza {
        radius: 12,
        toppings: vec![Topping::Tomato, Topping::Mozzarella],
    };
    order.push(margherita);

    let napoli = Pizza {
        radius: 12,
        toppings: vec![Topping::Tomato, Topping::Mozzarella, Topping::Anchovies],
    };
    order.push(napoli);

    let pizza = order.pop();
    assert!(pizza.is_some());
}

#[test]
fn items() {
    #[derive(Clone, PartialEq, Eq, Debug)]
    struct Point {
        x: i32,
        y: i32,
        cost: Vec<u32>,
    }

    let mut points = MultiArrayList::<Point>::new();
    assert_eq!(0, points.len());

    let mut cost = vec![17];
    points.push(Point {
        x: 1,
        y: 0,
        cost: cost.clone(),
    });

    cost.push(18);
    points.push(Point {
        x: 2,
        y: 0,
        cost: cost.clone(),
    });

    cost.push(19);
    points.push(Point {
        x: 3,
        y: 0,
        cost: cost.clone(),
    });

    cost.push(20);
    points.push(Point {
        x: 4,
        y: 0,
        cost: cost.clone(),
    });
    assert_eq!(4, points.len());

    let point_x = points.items::<"x", i32>();
    for (xval, exp) in point_x.zip(1..) {
        assert_eq!(exp, *xval);
        assert!(exp <= 4);
    }

    let costs = points.items::<"cost", Vec<u32>>();

    let start = 17;
    for (idx, cost) in costs.enumerate() {
        assert_eq!(idx + 1, cost.len());
        for (&c, exp) in cost.iter().zip(start..) {
            assert_eq!(exp, c);
        }
    }
}

#[test]
fn iter() {
    let mut points = MultiArrayList::<Point>::new();
    assert_eq!(0, points.len());
    assert_eq!(0, points.iter().count());

    points.push(Point { x: 1, y: 0 });
    points.push(Point { x: 2, y: 0 });
    points.push(Point { x: 3, y: 0 });
    points.push(Point { x: 4, y: 0 });
    assert_eq!(4, points.len());

    let it = points.iter();

    for (pt, exp) in it.zip(1..) {
        assert_eq!(exp, *pt.get::<"x", _>());
        assert_eq!(0, *pt.get::<"y", _>());
    }
}

#[test]
fn cheese() {
    // Based on the example from https://github.com/lumol-org/soa-derive

    #[allow(dead_code)]
    struct Cheese {
        pub smell: f64,
        pub color: (f64, f64, f64),
        pub with_mushrooms: bool,
        pub name: String,
    }

    impl Cheese {
        fn new(name: &str) -> Cheese {
            Cheese {
                smell: 0.2,
                color: (0., 1.0, 0.5),
                with_mushrooms: false,
                name: name.to_string(),
            }
        }
    }

    let mut cheeses = MultiArrayList::new();
    cheeses.push(Cheese::new("stilton"));
    cheeses.push(Cheese::new("brie"));

    for cheese in cheeses.iter() {
        let name = cheese.get::<"name", String>();
        assert!(!name.is_empty());
    }

    for cheese_name in cheeses.items::<"name", String>() {
        assert!(!cheese_name.is_empty());
    }
}

#[test]
fn mutable() {
    let mut order = MultiArrayList::<Pizza>::new();

    let margherita = Pizza {
        radius: 12,
        toppings: vec![Topping::Tomato],
    };
    order.push(margherita);

    let napoli = Pizza {
        radius: 12,
        toppings: vec![Topping::Tomato, Topping::Anchovies],
    };
    order.push(napoli);

    for toppings in order.items_mut::<"toppings", Vec<Topping>>() {
        toppings.push(Topping::Mozzarella);
    }

    for item in order.iter() {
        let toppings = item.get::<"toppings", Vec<Topping>>();
        assert!(toppings.contains(&Topping::Mozzarella));
    }
}

#[test]
fn bigger_alignment() {
    #[derive(Debug, PartialEq, Eq)]
    struct Integer {
        x: u128,
    }

    let mut numbers = MultiArrayList::<Integer>::new();

    let fortytwo = Integer { x: 42 };
    numbers.push(fortytwo);

    assert_eq!(Some(&Integer { x: 42 }), numbers.pop().as_deref());
}

#[test]
fn many_fields() {
    #[derive(Debug, Default, PartialEq, Eq)]
    struct Many {
        x0: u32,
        x1: u32,
        x2: u32,
        x3: u32,
        x4: u32,
        x5: u32,
        x6: u32,
        x7: u32,
        x8: u32,
        x9: u32,
    }

    let mut numbers = MultiArrayList::<Many>::new();

    let mut fortytwo = Many::default();
    fortytwo.x0 = 42;
    numbers.push(fortytwo);

    let mut expected = Many::default();
    expected.x0 = 42;
    assert_eq!(Some(&expected), numbers.pop().as_deref());
}