makepad_live_id/
live_id.rs

1#![allow(dead_code)]
2
3use {
4    std::{
5        sync::atomic::{AtomicU64, Ordering},
6        ops::{Index, IndexMut, Deref, DerefMut},
7        collections::{HashMap},
8        sync::Once,
9        fmt,
10        cmp,
11    }
12};
13
14
15impl LiveIdInterner {
16    pub fn add(&mut self, val: &str) {
17        self.id_to_string.insert(LiveId::from_str(val), val.to_string());
18    }
19    
20    pub fn contains(&mut self, val: &str) -> bool {
21        self.id_to_string.contains_key(&LiveId::from_str(val))
22    }
23    
24    pub fn with<F, R>(f: F) -> R
25    where
26    F: FnOnce(&mut Self) -> R,
27    {
28        static mut IDMAP: Option<LiveIdInterner> = None;
29        static ONCE: Once = Once::new();
30        ONCE.call_once( || unsafe {
31            let mut map = LiveIdInterner {
32                //alloc: 0,
33                id_to_string: HashMap::new()
34            };
35            // pre-seed list for debugging purposes
36            let fill = [
37                "default",
38                "exp",
39                "void",
40                "true",
41                "false",
42                "use",
43                "#",
44                "$",
45                "@",
46                "^",
47                "^=",
48                "|",
49                "||",
50                "|=",
51                "%",
52                "%=",
53                "!=",
54                "!",
55                "&&",
56                "*=",
57                "*",
58                "+=",
59                "+",
60                ",",
61                "-=",
62                "->",
63                "-",
64                "..",
65                "...",
66                "..=",
67                ".",
68                "/=",
69                "/",
70                "::",
71                ":",
72                ";",
73                "<=",
74                "<",
75                "<<",
76                "<<=",
77                "==",
78                "=",
79                ">=",
80                "=>",
81                ">",
82                ">>",
83                ">>=",
84                "?",
85                "tracks",
86                "state",
87                "state_id",
88                "user",
89                "play",
90                "ended"
91            ];
92            for item in &fill {
93                if map.contains(item) {
94                    eprintln!("WE HAVE AN ID COLLISION!");
95                }
96                map.add(item);
97            }
98            IDMAP = Some(map)
99        });
100        f(unsafe {IDMAP.as_mut().unwrap()})
101    }
102}
103
104#[derive(Clone, Default, Eq, Hash, Copy, PartialEq)]
105pub struct LiveId(pub u64);
106
107pub const LIVE_ID_SEED:u64 = 0xd6e8_feb8_6659_fd93;
108
109impl LiveId {
110    pub fn empty() -> Self {
111        Self (0)
112    }
113    pub fn from_lo_hi(lo:u32, hi:u32)->Self{
114        Self( (lo as u64) | ((hi as u64)<<32) )
115    }
116    pub fn lo(&self)->u32{
117        (self.0&0xffff_ffff) as u32
118    }
119    pub fn hi(&self)->u32{
120        (self.0>>32) as u32
121    }
122    
123    pub fn seeded()->Self{
124        Self(LIVE_ID_SEED)
125    }
126    
127    pub fn is_unique(&self) -> bool {
128        (self.0 & 0x8000_0000_0000_0000) == 0 && self.0 != 0
129    }
130    
131    pub fn is_ident(&self) -> bool {
132        (self.0 & 0x8000_0000_0000_0000) != 0
133    }
134    
135    pub fn is_empty(&self) -> bool {
136        self.0 == 0
137    }
138
139    pub fn get_value(&self) -> u64 {
140        self.0
141    }
142    
143    // from https://nullprogram.com/blog/2018/07/31/
144    // i have no idea what im doing with start value and finalisation.
145    pub const fn from_bytes(seed:u64, id_bytes: &[u8], start: usize, end: usize) -> Self {
146        let mut x = seed;
147        let mut i = start;
148        while i < end {
149            x = x.overflowing_add(id_bytes[i] as u64).0;
150            x ^= x >> 32;
151            x = x.overflowing_mul(0xd6e8_feb8_6659_fd93).0;
152            x ^= x >> 32;
153            x = x.overflowing_mul(0xd6e8_feb8_6659_fd93).0;
154            x ^= x >> 32;
155            i += 1;
156        }
157        // mark high bit as meaning that this is a hash id
158        Self ((x & 0x7fff_ffff_ffff_ffff) | 0x8000_0000_0000_0000)
159    }
160    
161    pub const fn from_str(id_str: &str) -> Self {
162        let bytes = id_str.as_bytes();
163        Self::from_bytes(LIVE_ID_SEED, bytes, 0, bytes.len())
164    }
165    
166    pub const fn str_append(self, id_str: &str) -> Self {
167        let bytes = id_str.as_bytes();
168        Self::from_bytes(self.0, bytes, 0, bytes.len())
169    }
170
171    pub const fn bytes_append(self, bytes: &[u8]) -> Self {
172        Self::from_bytes(self.0, bytes, 0, bytes.len())
173    }
174    
175    pub const fn id_append(self, id: LiveId) -> Self {
176        let bytes = id.0.to_be_bytes();
177        Self::from_bytes(self.0, &bytes, 0, bytes.len())
178    }
179    
180    pub const fn from_str_num(id_str: &str, num:u64) -> Self {
181        let bytes = id_str.as_bytes();
182        let id = Self::from_bytes(LIVE_ID_SEED, bytes, 0, bytes.len());
183        Self::from_bytes(id.0, &num.to_be_bytes(), 0, 8)
184    }
185    
186    pub const fn from_num(seed:u64, num:u64) -> Self {
187        Self::from_bytes(seed, &num.to_be_bytes(), 0, 8)
188    }
189    
190    pub fn from_str_with_lut(id_str: &str) -> Result<Self,
191    String> {
192        let id = Self::from_str(id_str);
193        LiveIdInterner::with( | idmap | {
194            if let Some(stored) = idmap.id_to_string.get(&id) {
195                if stored != id_str {
196                    return Err(stored.clone())
197                }
198            }
199            else {
200                idmap.id_to_string.insert(id, id_str.to_string());
201            }
202            Ok(id)
203        })
204    }
205    
206    pub fn from_str_num_with_lut(id_str: &str, num:u64) -> Result<Self,
207    String> {
208        let id = Self::from_str_num(id_str, num);
209        LiveIdInterner::with( | idmap | {
210            idmap.id_to_string.insert(id, format!("{}{}",id_str, num));
211            Ok(id)
212        })
213    }
214    
215    pub fn as_string<F, R>(&self, f: F) -> R
216    where F: FnOnce(Option<&str>) -> R
217    {
218        LiveIdInterner::with( | idmap | {
219            match idmap.id_to_string.get(self){
220                Some(v)=>f(Some(v)),
221                None=>f(None)
222            }
223        })
224    }
225
226    pub fn unique() -> Self {
227        LiveId(UNIQUE_LIVE_ID.fetch_add(1, Ordering::SeqCst))
228    }
229}
230
231pub (crate) static UNIQUE_LIVE_ID: AtomicU64 = AtomicU64::new(1);
232
233impl Ord for LiveId {
234    fn cmp(&self, other: &LiveId) -> cmp::Ordering {
235        LiveIdInterner::with( | idmap | {
236            if let Some(id1) = idmap.id_to_string.get(self) {
237                if let Some(id2) = idmap.id_to_string.get(other) {
238                    return id1.cmp(id2)
239                }
240            }
241            cmp::Ordering::Equal
242        })
243    }
244}
245
246impl PartialOrd for LiveId {
247    fn partial_cmp(&self, other: &LiveId) -> Option<cmp::Ordering> {
248        Some(self.cmp(other))
249    }
250}
251
252impl fmt::Debug for LiveId {
253    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254        fmt::Display::fmt(self, f)
255    }
256}
257
258impl fmt::Display for LiveId {
259    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260        if *self == LiveId::empty() {
261            write!(f, "0")
262        }
263        else if self.is_unique(){
264            write!(f, "UniqueId {}", self.0)
265        }
266        else{
267            self.as_string( | string | {
268                if let Some(id) = string {
269                    write!(f, "{}", id)
270                }
271                else {
272                    write!(f, "IdNotFound {:016x}", self.0)
273                }
274            })
275        }
276    }
277}
278
279impl fmt::LowerHex for LiveId {
280    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281        fmt::Display::fmt(self, f)
282    }
283}
284
285
286pub struct LiveIdInterner {
287    //alloc: u64,
288    id_to_string: HashMap<LiveId, String>,
289}
290
291// ----------------------------------------------------------------------------
292
293// Idea taken from the `nohash_hasher` crate.
294#[derive(Default)]
295pub struct LiveIdHasher(u64);
296
297impl std::hash::Hasher for LiveIdHasher {
298    fn write(&mut self, _: &[u8]) {
299        unreachable!("Invalid use of IdHasher");
300    }
301    
302    fn write_u8(&mut self, _n: u8) {
303        unreachable!("Invalid use of IdHasher");
304    }
305    fn write_u16(&mut self, _n: u16) {
306        unreachable!("Invalid use of IdHasher");
307    }
308    fn write_u32(&mut self, _n: u32) {
309        unreachable!("Invalid use of IdHasher");
310    }
311    
312    #[inline(always)]
313    fn write_u64(&mut self, n: u64) {
314        self.0 = n;
315    }
316    
317    fn write_usize(&mut self, _n: usize) {
318        unreachable!("Invalid use of IdHasher");
319    }
320    
321    fn write_i8(&mut self, _n: i8) {
322        unreachable!("Invalid use of IdHasher");
323    }
324    fn write_i16(&mut self, _n: i16) {
325        unreachable!("Invalid use of IdHasher");
326    }
327    fn write_i32(&mut self, _n: i32) {
328        unreachable!("Invalid use of IdHasher");
329    }
330    fn write_i64(&mut self, _n: i64) {
331        unreachable!("Invalid use of IdHasher");
332    }
333    fn write_isize(&mut self, _n: isize) {
334        unreachable!("Invalid use of IdHasher");
335    }
336    
337    #[inline(always)]
338    fn finish(&self) -> u64 {
339        self.0
340    }
341}
342
343#[derive(Copy, Clone, Default)]
344pub struct LiveIdHasherBuilder {}
345
346impl std::hash::BuildHasher for LiveIdHasherBuilder {
347    type Hasher = LiveIdHasher;
348    
349    #[inline(always)]
350    fn build_hasher(&self) -> LiveIdHasher {
351        LiveIdHasher::default()
352    }
353}
354
355#[derive(Clone, Debug)]
356pub struct LiveIdMap<K, V> {
357    map: HashMap<K, V, LiveIdHasherBuilder>,
358    //alloc_set: HashSet<K, LiveIdHasherBuilder>
359}
360
361impl<K, V> Default for LiveIdMap<K, V>
362where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId> + std::fmt::Debug {
363    fn default() -> Self {
364        Self {
365            map: HashMap::with_hasher(LiveIdHasherBuilder {}),
366            //alloc_set: HashSet::with_hasher(LiveIdHasherBuilder {})
367        }
368    }
369}
370/*
371impl<K, V> LiveIdMap<K, V>
372where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId> + std::fmt::Debug
373{
374    pub fn new() -> Self {Self::default()}
375    
376    pub fn alloc_key(&mut self) -> K {
377        loop {
378            let new_id = LiveId::unique().into();
379            if self.map.get(&new_id).is_none() && !self.alloc_set.contains(&new_id) {
380                self.alloc_set.insert(new_id);
381                return new_id
382            }
383        }
384    }
385    
386    pub fn insert_unique(&mut self, value: V) -> K {
387        loop {
388            let new_id = LiveId::unique().into();
389            if self.alloc_set.contains(&new_id) {
390                continue
391            }
392            match self.map.entry(new_id) {
393                Entry::Occupied(_) => continue,
394                Entry::Vacant(v) => {
395                    
396                    v.insert(value);
397                    return new_id
398                }
399            }
400        }
401    }
402    
403    pub fn insert(&mut self, k: impl Into<K>, value: V) {
404        let k = k.into();
405        self.alloc_set.remove(&k);
406        match self.map.entry(k) {
407            Entry::Occupied(_) => panic!("Item {:?} already inserted",k),
408            Entry::Vacant(v) => v.insert(value)
409        };
410    }
411}
412*/
413impl<K, V> Deref for LiveIdMap<K, V>
414where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId>
415{
416    type Target = HashMap<K, V, LiveIdHasherBuilder>;
417    fn deref(&self) -> &Self::Target {&self.map}
418}
419
420impl<K, V> DerefMut for LiveIdMap<K, V>
421where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId>
422{
423    fn deref_mut(&mut self) -> &mut Self::Target {&mut self.map}
424}
425
426impl<K, V> Index<K> for LiveIdMap<K, V>
427where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId>
428{
429    type Output = V;
430    fn index(&self, index: K) -> &Self::Output {
431        self.map.get(&index).unwrap()
432    }
433}
434
435impl<K, V> IndexMut<K> for LiveIdMap<K, V>
436where K: std::cmp::Eq + std::hash::Hash + Copy + From<LiveId>
437{
438    fn index_mut(&mut self, index: K) -> &mut Self::Output {
439        self.map.get_mut(&index).unwrap()
440    }
441}