1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::hash::{Hash, Hasher};

/// `Entity` type, as seen by the user.
#[derive(Clone, Copy)]
pub struct Entity(EntityRaw);

/// Index of the entity.
pub type Index = u32;

/// Generation of the entity.
pub type Generation = u32;

/// Raw data of the entity.
#[repr(C, packed)]
#[derive(Clone, Copy)]
union EntityRaw {
    id: u64,
    data: EntityData,
}

#[repr(C, packed)]
#[derive(Clone, Copy)]
struct EntityData {
    index: Index,
    generation: Generation,
}

impl Entity {
    /// Create new entity with the given ID.
    pub fn from_id(id: u64) -> Self {
        Self(EntityRaw { id })
    }

    /// Create new entity with the given given index and generation.
    pub fn from_parts(index: Index, generation: Generation) -> Self {
        Self(EntityRaw {
            data: EntityData { index, generation },
        })
    }

    /// Get the id of the entity.
    #[inline]
    pub fn id(&self) -> u64 {
        unsafe { self.0.id }
    }

    /// Get the index of the entity.
    #[inline]
    pub fn index(&self) -> Index {
        unsafe { self.0.data.index }
    }

    // Get the generation of the entity.
    #[inline]
    pub fn generation(&self) -> Generation {
        unsafe { self.0.data.generation }
    }
}

impl Display for Entity {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        write!(f, "{:08X}", self.id())
    }
}

impl Debug for Entity {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        write!(f, "{:08X}", self.id())
    }
}

impl Hash for Entity {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.index().hash(state);
        self.generation().hash(state);
    }
}

impl Eq for Entity {}

impl PartialEq<Entity> for Entity {
    fn eq(&self, other: &Entity) -> bool {
        self.id() == other.id()
    }
}

impl Ord for Entity {
    fn cmp(&self, other: &Self) -> Ordering {
        if self.generation() < other.generation() {
            Ordering::Less
        } else if self.generation() > other.generation() {
            Ordering::Greater
        } else if self.index() < other.index() {
            Ordering::Less
        } else if self.index() > other.index() {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

impl PartialOrd for Entity {
    fn partial_cmp(&self, other: &Entity) -> Option<Ordering> {
        Some(Ord::cmp(self, other))
    }
}