1use crate::engine;
2
3#[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 pub fn as_str(&self) -> &str {
22 &self.text
23 }
24
25 pub fn is_empty(&self) -> bool {
27 self.text.is_empty()
28 }
29}
30
31#[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 #[inline]
43 pub fn new(label: &'static str) -> Id {
44 Self::new_index(label, 0)
45 }
46
47 #[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 assert_eq!(a.base_id, b.base_id);
106 }
107}