summaryrefslogtreecommitdiff
path: root/ecs/src/uid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/uid.rs')
-rw-r--r--ecs/src/uid.rs168
1 files changed, 165 insertions, 3 deletions
diff --git a/ecs/src/uid.rs b/ecs/src/uid.rs
index c3ed85b..6c97649 100644
--- a/ecs/src/uid.rs
+++ b/ecs/src/uid.rs
@@ -1,23 +1,28 @@
-use std::fmt::{Debug, Formatter};
+use std::fmt::{Debug, Display, Formatter};
use std::mem::transmute;
use std::sync::atomic::{AtomicU32, Ordering};
+use crate::component::Component;
use crate::util::{gen_mask_64, BitMask, NumberExt};
-static NEXT: AtomicU32 = AtomicU32::new(1);
+static NEXT: AtomicU32 = AtomicU32::new(Uid::FIRST_UNIQUE_ID);
+
+static WILDCARD_ID: u32 = 1;
const ID_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(32..=63));
+const RELATION_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(6..=31));
const KIND_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(0..=1));
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum Kind
{
+ Pair = 3,
Entity = 2,
Component = 1,
}
-/// Unique entity/component ID.
+/// A unique identifier.
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Uid
{
@@ -26,6 +31,10 @@ pub struct Uid
impl Uid
{
+ /// The id part of the first unique `Uid`. The ids `0..Uid::FIRST_UNIQUE_ID` are
+ /// reserved.
+ pub const FIRST_UNIQUE_ID: u32 = 5;
+
/// Returns a new unique entity/component ID.
pub fn new_unique(kind: Kind) -> Self
{
@@ -37,6 +46,37 @@ impl Uid
}
#[must_use]
+ pub fn wildcard() -> Self
+ {
+ Self {
+ inner: ID_BITS.field_prep(u64::from(WILDCARD_ID))
+ | KIND_BITS.field_prep(Kind::Component as u64),
+ }
+ }
+
+ #[must_use]
+ pub fn new_pair(params: PairParams) -> Self
+ {
+ assert_ne!(
+ params.relation.kind(),
+ Kind::Pair,
+ "Pair relation cannot be a pair"
+ );
+
+ assert_ne!(
+ params.target.kind(),
+ Kind::Pair,
+ "Pair target cannot be a pair"
+ );
+
+ Self {
+ inner: ID_BITS.field_prep(u64::from(params.target.id()))
+ | RELATION_BITS.field_prep(u64::from(params.relation.id()))
+ | KIND_BITS.field_prep(Kind::Pair as u64),
+ }
+ }
+
+ #[must_use]
pub fn id(&self) -> u32
{
let Ok(id) = u32::try_from(self.inner.field_get(ID_BITS)) else {
@@ -57,6 +97,76 @@ impl Uid
// in the new_unique function
unsafe { transmute::<u8, Kind>(kind) }
}
+
+ /// If this `Uid` is a pair, returns the relation as a component `Uid`.
+ ///
+ /// # Panics
+ /// Will panic if this `Uid` is not a pair.
+ pub fn relation_component(&self) -> Self
+ {
+ assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair");
+
+ Self {
+ inner: ID_BITS.field_prep(u64::from(self.relation()))
+ | KIND_BITS.field_prep(Kind::Component as u64),
+ }
+ }
+
+ pub fn has_same_relation_as(&self, other: Self) -> bool
+ {
+ self.relation() == other.relation()
+ }
+
+ /// If this `Uid` is a pair, returns the relation as a entity `Uid`.
+ ///
+ /// # Panics
+ /// Will panic if this `Uid` is not a pair.
+ pub fn relation_entity(&self) -> Self
+ {
+ assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair");
+
+ Self {
+ inner: ID_BITS.field_prep(u64::from(self.relation()))
+ | KIND_BITS.field_prep(Kind::Entity as u64),
+ }
+ }
+
+ /// If this `Uid` is a pair, returns the target as a component `Uid`.
+ ///
+ /// # Panics
+ /// Will panic if this `Uid` is not a pair.
+ pub fn target_component(&self) -> Self
+ {
+ assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair");
+
+ Self {
+ inner: ID_BITS.field_prep(u64::from(self.id()))
+ | KIND_BITS.field_prep(Kind::Component as u64),
+ }
+ }
+
+ /// If this `Uid` is a pair, returns the target as a entity `Uid`.
+ ///
+ /// # Panics
+ /// Will panic if this `Uid` is not a pair.
+ pub fn target_entity(&self) -> Self
+ {
+ assert_eq!(self.kind(), Kind::Pair, "Uid is not a pair");
+
+ Self {
+ inner: ID_BITS.field_prep(u64::from(self.id()))
+ | KIND_BITS.field_prep(Kind::Entity as u64),
+ }
+ }
+
+ fn relation(&self) -> u32
+ {
+ let Ok(relation) = u32::try_from(self.inner.field_get(RELATION_BITS)) else {
+ unreachable!("Uid relation does not fit in u32");
+ };
+
+ relation
+ }
}
impl Debug for Uid
@@ -70,3 +180,55 @@ impl Debug for Uid
.finish_non_exhaustive()
}
}
+
+impl Display for Uid
+{
+ fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result
+ {
+ if self.kind() == Kind::Pair {
+ return write!(
+ formatter,
+ "({}, {})",
+ self.relation(),
+ self.target_component()
+ );
+ }
+
+ if *self == Uid::wildcard() {
+ return write!(formatter, "*");
+ }
+
+ write!(formatter, "{}", self.id())
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct PairParams
+{
+ pub relation: Uid,
+ pub target: Uid,
+}
+
+pub trait With: 'static
+{
+ fn uid() -> Uid;
+}
+
+impl<ComponentT: Component> With for ComponentT
+{
+ fn uid() -> Uid
+ {
+ Self::id()
+ }
+}
+
+#[derive(Debug)]
+pub enum Wildcard {}
+
+impl With for Wildcard
+{
+ fn uid() -> Uid
+ {
+ Uid::wildcard()
+ }
+}