Skip to main content

ply_engine/
id.rs

1use crate::engine;
2
3/// Owned string for debug/display purposes.
4#[derive(Debug, Clone, Default, PartialEq)]
5pub struct StringId {
6    text: String,
7}
8
9impl StringId {
10    pub fn from_str(s: &str) -> Self {
11        Self {
12            text: s.to_string(),
13        }
14    }
15
16    pub fn empty() -> Self {
17        Self::default()
18    }
19
20    /// Get the string content.
21    pub fn as_str(&self) -> &str {
22        &self.text
23    }
24
25    /// Returns true if the string is empty.
26    pub fn is_empty(&self) -> bool {
27        self.text.is_empty()
28    }
29}
30
31/// A hashed identifier used to uniquely address UI elements across frames.
32#[derive(Debug, Clone, Default, PartialEq)]
33pub struct Id {
34    pub id: u32,
35    pub offset: u32,
36    pub base_id: u32,
37    pub string_id: StringId,
38}
39
40impl Id {
41    /// Creates a ply id using the `label`
42    #[inline]
43    pub fn new(label: &'static str) -> Id {
44        Self::new_index(label, 0)
45    }
46
47    /// Creates a ply id using the `label` and the `index`
48    #[inline]
49    pub fn new_index(label: &'static str, index: u32) -> Id {
50        engine::hash_string_with_offset(label, index, 0)
51    }
52
53    #[inline]
54    pub fn new_index_seed(label: &'static str, index: u32, seed: u32) -> Id {
55        engine::hash_string_with_offset(label, index, seed)
56    }
57}
58
59impl From<&'static str> for Id {
60    fn from(label: &'static str) -> Self {
61        Id::new(label)
62    }
63}
64
65impl From<(&str, u32)> for Id {
66    fn from((label, offset): (&str, u32)) -> Self {
67        engine::hash_string_with_offset(label, offset, 0)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn from_str_matches_new() {
77        let a = Id::from("hello");
78        let b = Id::new("hello");
79        assert_eq!(a.id, b.id);
80        assert_eq!(a.base_id, b.base_id);
81    }
82
83    #[test]
84    fn from_tuple_matches_new_index() {
85        let a = Id::from(("my_button", 3));
86        let b = Id::new_index("my_button", 3);
87        assert_eq!(a.id, b.id);
88        assert_eq!(a.offset, b.offset);
89        assert_eq!(a.base_id, b.base_id);
90    }
91
92    #[test]
93    fn from_tuple_zero_offset_matches_from_str() {
94        let a = Id::from(("test", 0));
95        let b = Id::from("test");
96        assert_eq!(a.id, b.id);
97    }
98
99    #[test]
100    fn different_offsets_produce_different_ids() {
101        let a = Id::from(("item", 0));
102        let b = Id::from(("item", 1));
103        assert_ne!(a.id, b.id);
104        // But base_id should be the same (pre-offset hash)
105        assert_eq!(a.base_id, b.base_id);
106    }
107}