Skip to main content

waremax_core/
id.rs

1//! Typed ID wrappers for type-safe entity references
2
3use rkyv::{Archive, Deserialize, Serialize};
4use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
5use std::fmt;
6use std::hash::Hash;
7
8/// Macro to define typed ID wrappers
9macro_rules! define_id {
10    ($name:ident, $doc:expr) => {
11        #[doc = $doc]
12        #[derive(
13            Archive,
14            Deserialize,
15            Serialize,
16            SerdeDeserialize,
17            SerdeSerialize,
18            Clone,
19            Copy,
20            PartialEq,
21            Eq,
22            Hash,
23            Default,
24        )]
25        #[rkyv(compare(PartialEq))]
26        pub struct $name(pub u32);
27
28        impl $name {
29            /// Create a new ID from a u32 value
30            #[inline]
31            pub const fn new(id: u32) -> Self {
32                Self(id)
33            }
34
35            /// Get the inner u32 value
36            #[inline]
37            pub const fn as_u32(&self) -> u32 {
38                self.0
39            }
40        }
41
42        impl fmt::Debug for $name {
43            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44                write!(f, "{}({})", stringify!($name), self.0)
45            }
46        }
47
48        impl fmt::Display for $name {
49            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50                write!(f, "{}", self.0)
51            }
52        }
53
54        impl From<u32> for $name {
55            fn from(id: u32) -> Self {
56                Self(id)
57            }
58        }
59
60        impl From<$name> for u32 {
61            fn from(id: $name) -> Self {
62                id.0
63            }
64        }
65    };
66}
67
68define_id!(RobotId, "Unique identifier for a robot");
69define_id!(NodeId, "Unique identifier for a map node");
70define_id!(EdgeId, "Unique identifier for a map edge");
71define_id!(StationId, "Unique identifier for a station");
72define_id!(RackId, "Unique identifier for a storage rack");
73define_id!(BinId, "Unique identifier for a storage bin");
74define_id!(SkuId, "Unique identifier for a SKU");
75define_id!(OrderId, "Unique identifier for an order");
76define_id!(TaskId, "Unique identifier for a task");
77define_id!(EventId, "Unique identifier for a scheduled event");
78define_id!(
79    ShipmentId,
80    "Unique identifier for an inbound/outbound shipment"
81);
82define_id!(
83    ChargingStationId,
84    "Unique identifier for a charging station"
85);
86define_id!(
87    MaintenanceStationId,
88    "Unique identifier for a maintenance station"
89);
90
91/// ID generator for creating sequential IDs
92#[derive(Debug, Clone, Default)]
93pub struct IdGenerator<T> {
94    next: u32,
95    _marker: std::marker::PhantomData<T>,
96}
97
98impl<T> IdGenerator<T> {
99    /// Create a new ID generator starting from 0
100    pub fn new() -> Self {
101        Self {
102            next: 0,
103            _marker: std::marker::PhantomData,
104        }
105    }
106
107    /// Create a new ID generator starting from a specific value
108    pub fn starting_from(start: u32) -> Self {
109        Self {
110            next: start,
111            _marker: std::marker::PhantomData,
112        }
113    }
114
115    /// Get the next ID value without incrementing
116    pub fn peek(&self) -> u32 {
117        self.next
118    }
119}
120
121macro_rules! impl_id_generator {
122    ($id_type:ident) => {
123        impl IdGenerator<$id_type> {
124            /// Generate the next ID
125            pub fn next_id(&mut self) -> $id_type {
126                let id = $id_type(self.next);
127                self.next += 1;
128                id
129            }
130        }
131    };
132}
133
134impl_id_generator!(RobotId);
135impl_id_generator!(NodeId);
136impl_id_generator!(EdgeId);
137impl_id_generator!(StationId);
138impl_id_generator!(RackId);
139impl_id_generator!(BinId);
140impl_id_generator!(SkuId);
141impl_id_generator!(OrderId);
142impl_id_generator!(TaskId);
143impl_id_generator!(EventId);
144impl_id_generator!(ShipmentId);
145impl_id_generator!(ChargingStationId);
146impl_id_generator!(MaintenanceStationId);
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn test_id_generation() {
154        let mut gen = IdGenerator::<RobotId>::new();
155        assert_eq!(gen.next_id(), RobotId(0));
156        assert_eq!(gen.next_id(), RobotId(1));
157        assert_eq!(gen.next_id(), RobotId(2));
158    }
159
160    #[test]
161    fn test_id_equality() {
162        let id1 = RobotId(42);
163        let id2 = RobotId(42);
164        let id3 = RobotId(43);
165        assert_eq!(id1, id2);
166        assert_ne!(id1, id3);
167    }
168}