packo 0.3.1

Packed datastructure with self referential indexing.
Documentation
use std::{
    fmt::Display,
    mem::MaybeUninit,
    ops::{Add, Sub},
};

use packo::*;

const CAT_INVENTORY: usize = 0;
const CAT_SPELLS: usize = 1;

pub type Entities = Packo<256, Entity, 2, u8>;

#[derive(Clone, Copy, Default)]
#[repr(C)]
pub enum Component {
    #[default]
    None = 0,
    Spatial = 1 << 0,
    Player = 1 << 1,
    Life = 1 << 2,
    Damage = 1 << 3,
    Cost = 1 << 4,
    Consume = 1 << 5,
}

const ALL_COMPONENTS: [Component; 6] = [
    Component::Spatial,
    Component::Player,
    Component::Life,
    Component::Damage,
    Component::Cost,
    Component::Consume,
];

impl Add for Component {
    type Output = Components;

    fn add(self, rhs: Self) -> Self::Output {
        #[allow(clippy::suspicious_arithmetic_impl)]
        Components(self as u8 | rhs as u8)
    }
}

#[derive(Debug, Default)]
pub struct Components(u8);

impl Components {
    pub fn has(&self, t: Component) -> bool {
        self.0 & t as u8 > 0
    }

    pub fn add(&mut self, t: Component) {
        self.0 |= t as u8;
    }

    pub fn rem(&mut self, t: Component) {
        self.0 &= !(t as u8);
    }
}

impl From<Component> for Components {
    fn from(value: Component) -> Self {
        Components(value as u8)
    }
}

impl Add for Components {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        #[allow(clippy::suspicious_arithmetic_impl)]
        Components(self.0 | rhs.0)
    }
}

impl Sub for Components {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        #[allow(clippy::suspicious_arithmetic_impl)]
        Components(self.0 & !rhs.0)
    }
}

pub type VX = f32;

#[derive(Debug)]
pub struct Vec<const S: usize, T = VX>([T; S]);

impl<const S: usize, T> Default for Vec<S, T> {
    fn default() -> Self {
        Self(unsafe { MaybeUninit::zeroed().assume_init() })
    }
}

pub type Vec2i = Vec<2, u8>;
pub type Vec2 = Vec<2>;
pub type Vec3 = Vec<3>;
pub type Vec4 = Vec<4>;

#[derive(Debug, Default)]
pub struct Spatial {
    // pub translation: Vec3,
    // pub scale: Vec3,
    // pub rotation: Vec4,
    pub pos: Vec2i,
}

#[derive(Debug, Default)]
pub struct Entity {
    pub id: u8,
    pub components: Components,
    pub spatial: Spatial,
    pub life: u8,
    pub damage: u8,
    pub cost: u8,
}

impl Display for Entity {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "ID:{}//", self.id)?;
        for c in ALL_COMPONENTS {
            if self.components.has(c) {
                match c {
                    Component::Spatial => write!(
                        f,
                        "POS:{},{}//",
                        self.spatial.pos.0[0],
                        self.spatial.pos.0[1],
                        // "POS:{},{},{}//",
                        // self.spatial.translation.0[0],
                        // self.spatial.translation.0[1],
                        // self.spatial.translation.0[2]
                    )?,
                    Component::Player => f.write_str("Player//")?,
                    Component::Life => write!(f, "Life:{}//", self.life)?,
                    Component::Damage => write!(f, "Damage:{}//", self.damage)?,
                    Component::Cost => write!(f, "Cost:{}//", self.cost)?,
                    Component::Consume => write!(f, "Consumable//")?,
                    _ => {}
                };
            }
        }
        Ok(())
    }
}

fn game_reset(e: &mut Entities) -> u8 {
    e.reset();

    let p = e.insert(Entity {
        components: Component::Player + Component::Spatial + Component::Life.into(),
        life: 100,
        ..Default::default()
    });
    e[p].id = p;

    let potion = e.nestc(
        p,
        CAT_INVENTORY,
        Entity {
            components: Component::Life + Component::Consume,
            life: 50,
            ..Default::default()
        },
    );
    e[potion].id = potion;

    let firebolt = e.nestc(
        p,
        CAT_SPELLS,
        Entity {
            components: Component::Damage + Component::Cost,
            damage: 10,
            cost: 5,
            ..Default::default()
        },
    );
    e[firebolt].id = firebolt;

    let heal = e.nestc(
        p,
        CAT_SPELLS,
        Entity {
            components: Component::Life + Component::Cost,
            life: 10,
            cost: 5,
            ..Default::default()
        },
    );
    e[heal].id = heal;

    p
}

fn main() {
    let mut e = Entities::default();
    let p = game_reset(&mut e);

    println!("Player: {}", e[p]);
    for e in e.childsc(p, CAT_INVENTORY) {
        println!("Item: {e}");
    }
    for e in e.childsc(p, CAT_SPELLS) {
        println!("Spell: {e}");
    }

    println!("{e}");
}