Skip to main content

steel_registry/
ticket_type.rs

1use bitflags::bitflags;
2use rustc_hash::FxHashMap;
3use steel_utils::Identifier;
4
5bitflags! {
6    /// Properties that control a ticket's loading, simulation, and persistence behavior.
7    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
8    pub struct TicketTypeFlags: u32 {
9        const PERSIST = 1 << 0;
10        const LOADING = 1 << 1;
11        const SIMULATION = 1 << 2;
12        const KEEP_DIMENSION_ACTIVE = 1 << 3;
13        const CAN_EXPIRE_IF_UNLOADED = 1 << 4;
14    }
15}
16
17/// A registered chunk ticket kind.
18#[derive(Debug)]
19pub struct TicketType {
20    pub key: Identifier,
21    timeout: i64,
22    flags: TicketTypeFlags,
23}
24
25impl TicketType {
26    /// Vanilla's sentinel for a ticket that never expires based on elapsed ticks.
27    pub const NO_TIMEOUT: i64 = 0;
28
29    #[must_use]
30    pub const fn new(key: Identifier, timeout: i64, flags: TicketTypeFlags) -> Self {
31        Self {
32            key,
33            timeout,
34            flags,
35        }
36    }
37
38    #[must_use]
39    pub const fn timeout(&self) -> i64 {
40        self.timeout
41    }
42
43    #[must_use]
44    pub const fn flags(&self) -> TicketTypeFlags {
45        self.flags
46    }
47
48    #[must_use]
49    pub const fn persist(&self) -> bool {
50        self.flags.contains(TicketTypeFlags::PERSIST)
51    }
52
53    #[must_use]
54    pub const fn does_load(&self) -> bool {
55        self.flags.contains(TicketTypeFlags::LOADING)
56    }
57
58    #[must_use]
59    pub const fn does_simulate(&self) -> bool {
60        self.flags.contains(TicketTypeFlags::SIMULATION)
61    }
62
63    #[must_use]
64    pub const fn should_keep_dimension_active(&self) -> bool {
65        self.flags.contains(TicketTypeFlags::KEEP_DIMENSION_ACTIVE)
66    }
67
68    #[must_use]
69    pub const fn can_expire_if_unloaded(&self) -> bool {
70        self.flags.contains(TicketTypeFlags::CAN_EXPIRE_IF_UNLOADED)
71    }
72
73    #[must_use]
74    pub const fn has_timeout(&self) -> bool {
75        self.timeout != Self::NO_TIMEOUT
76    }
77}
78
79pub type TicketTypeRef = &'static TicketType;
80
81/// Registry for vanilla and extension-defined chunk ticket kinds.
82pub struct TicketTypeRegistry {
83    ticket_types_by_id: Vec<TicketTypeRef>,
84    ticket_types_by_key: FxHashMap<Identifier, usize>,
85    allows_registering: bool,
86}
87
88impl TicketTypeRegistry {
89    #[must_use]
90    pub fn new() -> Self {
91        Self {
92            ticket_types_by_id: Vec::new(),
93            ticket_types_by_key: FxHashMap::default(),
94            allows_registering: true,
95        }
96    }
97}
98
99crate::impl_standard_methods!(
100    TicketTypeRegistry,
101    TicketTypeRef,
102    ticket_types_by_id,
103    ticket_types_by_key,
104    allows_registering,
105    "Cannot register duplicate ticket type key: {}"
106);
107
108crate::impl_registry!(
109    TicketTypeRegistry,
110    TicketType,
111    ticket_types_by_id,
112    ticket_types_by_key,
113    ticket_types
114);
115
116#[cfg(test)]
117mod tests {
118    use steel_utils::Identifier;
119
120    use super::{TicketType, TicketTypeFlags, TicketTypeRegistry};
121
122    static TEST_TICKET: TicketType = TicketType::new(
123        Identifier::new_static("test", "ticket"),
124        TicketType::NO_TIMEOUT,
125        TicketTypeFlags::LOADING,
126    );
127
128    #[test]
129    #[should_panic(expected = "Cannot register duplicate ticket type key")]
130    fn rejects_duplicate_keys() {
131        let mut registry = TicketTypeRegistry::new();
132        registry.register(&TEST_TICKET);
133        registry.register(&TEST_TICKET);
134    }
135}