1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12use std::{
13 hash::{BuildHasher, Hash, Hasher},
14 num::{NonZeroU32, NonZeroU64},
15 ops,
16 sync::atomic::{AtomicU32, Ordering},
17};
18
19use rayon::iter::{FromParallelIterator, IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator};
20
21#[doc(hidden)]
22#[cfg(target_has_atomic = "64")]
23pub use std::sync::atomic::AtomicU64;
24
25#[doc(hidden)]
26#[cfg(not(target_has_atomic = "64"))]
27pub struct AtomicU64(parking_lot::Mutex<u64>);
28#[cfg(not(target_has_atomic = "64"))]
29impl AtomicU64 {
30 pub const fn new(u: u64) -> Self {
31 Self(parking_lot::Mutex::new(u))
32 }
33
34 fn fetch_add(&self, u: u64, _: Ordering) -> u64 {
35 let mut a = self.0.lock();
36 let r = *a;
37 *a += u;
38 r
39 }
40}
41
42#[cfg(feature = "named")]
43mod named;
44
45#[doc(hidden)]
46pub mod hot_reload;
47
48pub use hot_reload::lazy_static_init;
49
50#[cfg(feature = "named")]
51pub use named::*;
52
53#[doc(hidden)]
54pub use pastey::paste;
55
56#[macro_export]
58macro_rules! unique_id_32 {
59 ($(#[$attrs:meta])* $vis:vis struct $Type:ident $(< $T:ident $(:($($bounds:tt)+))? >)? $(: $ParentId:path)? ;) => {
60 $crate::unique_id! {
61 request {
62 $(#[$attrs])*
63 #[doc=concat!("`Option<", stringify!($Type), ">`")]
68 #[doc=concat!("`", stringify!($Type), "`")]
70 $vis struct $Type $(< $T $(:($($bounds)+))? >)? $(: $ParentId)? ;
85 }
86 non_zero {
87 std::num::NonZeroU32
88 }
89 atomic {
90 std::sync::atomic::AtomicU32
91 }
92 next_id {
93 $crate::next_id32
94 }
95 literal {
96 u32
97 }
98 to_hash {
99 $crate::un_hash32
100 }
101 to_sequential {
102 $crate::un_hash32
103 }
104 }
105 }
106}
107
108#[macro_export]
110macro_rules! unique_id_64 {
111 ($(#[$attrs:meta])* $vis:vis struct $Type:ident $(< $T:ident $(:($($bounds:tt)+))? >)? $(: $ParentId:path)? ;) => {
112 $crate::unique_id! {
113 request {
114 $(#[$attrs])*
115 #[doc=concat!("`Option<", stringify!($Type), ">`")]
120 #[doc=concat!("`", stringify!($Type), "`")]
122 $vis struct $Type $(< $T $(:($($bounds)+))? >)? $(: $ParentId)? ;
136 }
137 non_zero {
138 std::num::NonZeroU64
139 }
140 atomic {
141 $crate::AtomicU64
142 }
143 next_id {
144 $crate::next_id64
145 }
146 literal {
147 u64
148 }
149 to_hash {
150 $crate::splitmix64
151 }
152 to_sequential {
153 $crate::un_splitmix64
154 }
155 }
156 };
157}
158
159#[macro_export]
163macro_rules! impl_unique_id_bytemuck {
164 ($Type:ident $(< $T:ident $(:($($bounds:tt)+))? >)?) => {
165 unsafe impl$(<$T $(: $($bounds)+)?>)? bytemuck::NoUninit for $Type $(<$T>)? { }
167 unsafe impl$(<$T $(: $($bounds)+)?>)? bytemuck::ZeroableInOption for $Type $(<$T>)? { }
168 unsafe impl$(<$T $(: $($bounds)+)?>)? bytemuck::PodInOption for $Type $(<$T>)? { }
169 }
170}
171
172#[doc(hidden)]
173#[macro_export]
174macro_rules! unique_id {
175 (
176 request {
177 $(#[$attrs:meta])* $vis:vis struct $Type:ident $(< $T:ident $(:($($bounds:tt)+))? >)? $(: $ParentId:path)? ;
178 }
179 non_zero {
180 $non_zero:path
181 }
182 atomic {
183 $atomic:path
184 }
185 next_id {
186 $next_id:path
187 }
188 literal {
189 $lit:ident
190 }
191 to_hash {
192 $to_hash:path
193 }
194 to_sequential {
195 $to_sequential:path
196 }
197 ) => {
198
199 $(#[$attrs])*
200 #[repr(transparent)]
201 $vis struct $Type $(<$T $(: $($bounds)+)?>)? ($non_zero $(, std::marker::PhantomData<$T>)?);
202
203 impl$(<$T $(: $($bounds)+)?>)? Clone for $Type $(<$T>)? {
204 fn clone(&self) -> Self {
205 *self
206 }
207 }
208 impl$(<$T $(: $($bounds)+)?>)? Copy for $Type $(<$T>)? {
209 }
210 impl$(<$T $(: $($bounds)+)?>)? PartialEq for $Type $(<$T>)? {
211 fn eq(&self, other: &Self) -> bool {
212 self.0 == other.0
213 }
214 }
215 impl$(<$T $(: $($bounds)+)?>)? Eq for $Type $(<$T>)? {
216 }
217 impl$(<$T $(: $($bounds)+)?>)? std::hash::Hash for $Type $(<$T>)? {
218 fn hash<H>(&self, state: &mut H)
219 where
220 H: std::hash::Hasher
221 {
222 std::hash::Hash::hash(&self.0, state)
223 }
224 }
225 impl$(<$T $(: $($bounds)+)?>)? $crate::UniqueId for $Type $(<$T>)? {
226 fn new_unique() -> Self {
227 Self::new_unique()
228 }
229 }
230
231 #[allow(dead_code)]
232 impl$(<$T $(: $($bounds)+)?>)? $Type $(<$T>)? {
233 $crate::unique_id! {
234 new_unique {
235 $($ParentId, )? $(<$T>)?
236 }
237 atomic {
238 $atomic
239 }
240 next_id {
241 $next_id
242 }
243 }
244
245 pub fn get(self) -> $lit {
247 self.0.get()
248 }
249
250 pub fn sequential(self) -> $lit {
254 $to_sequential(self.0.get())
255 }
256
257 pub fn from_raw(raw: $lit) -> Self {
264 use $non_zero as __non_zero;
265
266 Self(__non_zero::new(raw).unwrap() $(, std::marker::PhantomData::<$T>)?)
267 }
268
269 pub fn from_sequential(num: $lit) -> Self {
278 use $non_zero as __non_zero;
279
280 Self(__non_zero::new($to_hash(num)).unwrap() $(, std::marker::PhantomData::<$T>)?)
281 }
282 }
283 };
284
285 (
286 new_unique {
287 $ParentId:path, $(<$T:ident>)?
288 }
289 atomic {
290 $atomic:path
291 }
292 next_id {
293 $next_id:path
294 }
295 ) => {
296 pub fn new_unique() -> Self {
298 use $ParentId as __parent;
299 let id = __parent $(::<$T>)? ::new_unique().get();
300 Self::from_raw(id)
301 }
302 };
303
304 (
305 new_unique {
306 $(<$T:ident>)?
307 }
308 atomic {
309 $atomic:path
310 }
311 next_id {
312 $next_id:path
313 }
314 ) => {
315 pub fn new_unique() -> Self {
317 use $atomic as __atomic;
318
319 $crate::hot_static! {
320 static NEXT: __atomic = __atomic::new(1);
321 }
322 let __ref = $crate::hot_static_ref!(NEXT);
323 Self($next_id(__ref) $(, std::marker::PhantomData::<$T>)?)
324 }
325 };
326}
327
328#[doc(hidden)]
329pub fn next_id32(next: &'static AtomicU32) -> NonZeroU32 {
330 loop {
331 let id = next.fetch_add(1, Ordering::Relaxed);
333
334 if id == 0 {
335 tracing::error!("id factory reached `u32::MAX`, will start reusing");
336 } else {
337 let id = hash32(id);
338 if let Some(id) = NonZeroU32::new(id) {
339 return id;
340 }
341 }
342 }
343}
344#[doc(hidden)]
345pub fn next_id64(next: &'static AtomicU64) -> NonZeroU64 {
346 loop {
347 let id = next.fetch_add(1, Ordering::Relaxed);
349
350 if id == 0 {
351 tracing::error!("id factory reached `u64::MAX`, will start reusing");
352 } else {
353 let id = splitmix64(id);
355 if let Some(id) = NonZeroU64::new(id) {
356 return id;
357 }
358 }
359 }
360}
361
362#[doc(hidden)]
363pub fn hash32(n: u32) -> u32 {
364 use std::num::Wrapping as W;
365
366 let mut z = W(n);
367 z = ((z >> 16) ^ z) * W(0x45d9f3b);
368 z = ((z >> 16) ^ z) * W(0x45d9f3b);
369 z = (z >> 16) ^ z;
370 z.0
371}
372#[doc(hidden)]
373pub fn un_hash32(z: u32) -> u32 {
374 use std::num::Wrapping as W;
375
376 let mut n = W(z);
377 n = ((n >> 16) ^ n) * W(0x119de1f3);
378 n = ((n >> 16) ^ n) * W(0x119de1f3);
379 n = (n >> 16) ^ n;
380 n.0
381}
382
383#[doc(hidden)]
384pub fn splitmix64(n: u64) -> u64 {
385 use std::num::Wrapping as W;
386
387 let mut z = W(n);
388 z = (z ^ (z >> 30)) * W(0xBF58476D1CE4E5B9u64);
389 z = (z ^ (z >> 27)) * W(0x94D049BB133111EBu64);
390 z = z ^ (z >> 31);
391 z.0
392}
393#[doc(hidden)]
394pub fn un_splitmix64(z: u64) -> u64 {
395 use std::num::Wrapping as W;
396
397 let mut n = W(z);
398 n = (n ^ (n >> 31) ^ (n >> 62)) * W(0x319642b2d24d8ec3u64);
399 n = (n ^ (n >> 27) ^ (n >> 54)) * W(0x96de1b173f119089u64);
400 n = n ^ (n >> 30) ^ (n >> 60);
401 n.0
402}
403
404#[derive(Clone, Debug)]
406pub struct IdMap<K, V>(hashbrown::HashMap<K, V, BuildIdHasher>);
407impl<K, V> IdMap<K, V> {
408 pub const fn new() -> Self {
410 Self(hashbrown::HashMap::with_hasher(BuildIdHasher))
411 }
412}
413impl<K, V> Default for IdMap<K, V> {
414 fn default() -> Self {
415 Self::new()
416 }
417}
418impl<K, V> ops::Deref for IdMap<K, V> {
419 type Target = hashbrown::HashMap<K, V, BuildIdHasher>;
420
421 fn deref(&self) -> &Self::Target {
422 &self.0
423 }
424}
425impl<K, V> ops::DerefMut for IdMap<K, V> {
426 fn deref_mut(&mut self) -> &mut Self::Target {
427 &mut self.0
428 }
429}
430impl<K, V> IntoIterator for IdMap<K, V> {
431 type Item = (K, V);
432
433 type IntoIter = hashbrown::hash_map::IntoIter<K, V>;
434
435 fn into_iter(self) -> Self::IntoIter {
436 self.0.into_iter()
437 }
438}
439impl<'a, K, V> IntoIterator for &'a IdMap<K, V> {
440 type Item = (&'a K, &'a V);
441
442 type IntoIter = hashbrown::hash_map::Iter<'a, K, V>;
443
444 fn into_iter(self) -> Self::IntoIter {
445 self.0.iter()
446 }
447}
448impl<'a, K, V> IntoIterator for &'a mut IdMap<K, V> {
449 type Item = (&'a K, &'a mut V);
450
451 type IntoIter = hashbrown::hash_map::IterMut<'a, K, V>;
452
453 fn into_iter(self) -> Self::IntoIter {
454 self.0.iter_mut()
455 }
456}
457impl<K: Send, V: Send> IntoParallelIterator for IdMap<K, V> {
458 type Iter = hashbrown::hash_map::rayon::IntoParIter<K, V>;
459
460 type Item = (K, V);
461
462 fn into_par_iter(self) -> Self::Iter {
463 self.0.into_par_iter()
464 }
465}
466impl<'a, K: Sync, V: Sync> IntoParallelIterator for &'a IdMap<K, V> {
467 type Iter = hashbrown::hash_map::rayon::ParIter<'a, K, V>;
468
469 type Item = (&'a K, &'a V);
470
471 fn into_par_iter(self) -> Self::Iter {
472 self.0.par_iter()
473 }
474}
475impl<'a, K: Sync, V: Send> IntoParallelIterator for &'a mut IdMap<K, V> {
476 type Iter = hashbrown::hash_map::rayon::ParIterMut<'a, K, V>;
477
478 type Item = (&'a K, &'a mut V);
479
480 fn into_par_iter(self) -> Self::Iter {
481 self.0.par_iter_mut()
482 }
483}
484impl<K: Eq + Hash, V> FromIterator<(K, V)> for IdMap<K, V> {
485 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
486 Self(FromIterator::from_iter(iter))
487 }
488}
489impl<K: Eq + Hash + Send, V: Send> FromParallelIterator<(K, V)> for IdMap<K, V> {
490 fn from_par_iter<I>(par_iter: I) -> Self
491 where
492 I: IntoParallelIterator<Item = (K, V)>,
493 {
494 Self(FromParallelIterator::from_par_iter(par_iter))
495 }
496}
497
498#[derive(Clone, Debug)]
500pub struct IdSet<K>(hashbrown::HashSet<K, BuildIdHasher>);
501impl<K> IdSet<K> {
502 pub const fn new() -> Self {
504 Self(hashbrown::HashSet::with_hasher(BuildIdHasher))
505 }
506}
507impl<K> Default for IdSet<K> {
508 fn default() -> Self {
509 Self::new()
510 }
511}
512impl<K> ops::Deref for IdSet<K> {
513 type Target = hashbrown::HashSet<K, BuildIdHasher>;
514
515 fn deref(&self) -> &Self::Target {
516 &self.0
517 }
518}
519impl<K> ops::DerefMut for IdSet<K> {
520 fn deref_mut(&mut self) -> &mut Self::Target {
521 &mut self.0
522 }
523}
524impl<K> IntoIterator for IdSet<K> {
525 type Item = K;
526
527 type IntoIter = hashbrown::hash_set::IntoIter<K>;
528
529 fn into_iter(self) -> Self::IntoIter {
530 self.0.into_iter()
531 }
532}
533impl<'a, K> IntoIterator for &'a IdSet<K> {
534 type Item = &'a K;
535
536 type IntoIter = hashbrown::hash_set::Iter<'a, K>;
537
538 fn into_iter(self) -> Self::IntoIter {
539 self.0.iter()
540 }
541}
542impl<K: Send> IntoParallelIterator for IdSet<K> {
543 type Iter = hashbrown::hash_set::rayon::IntoParIter<K>;
544
545 type Item = K;
546
547 fn into_par_iter(self) -> Self::Iter {
548 self.0.into_par_iter()
549 }
550}
551impl<'a, K: Sync> IntoParallelIterator for &'a IdSet<K> {
552 type Iter = hashbrown::hash_set::rayon::ParIter<'a, K>;
553
554 type Item = &'a K;
555
556 fn into_par_iter(self) -> Self::Iter {
557 self.0.par_iter()
558 }
559}
560impl<K: Eq + Hash> FromIterator<K> for IdSet<K> {
561 fn from_iter<T: IntoIterator<Item = K>>(iter: T) -> Self {
562 Self(FromIterator::from_iter(iter))
563 }
564}
565impl<K: Eq + Hash + Send> FromParallelIterator<K> for IdSet<K> {
566 fn from_par_iter<I>(par_iter: I) -> Self
567 where
568 I: IntoParallelIterator<Item = K>,
569 {
570 Self(FromParallelIterator::from_par_iter(par_iter))
571 }
572}
573impl<K: Eq + Hash> PartialEq for IdSet<K> {
574 fn eq(&self, other: &Self) -> bool {
575 self.0 == other.0
576 }
577}
578impl<K: Eq + Hash> Eq for IdSet<K> {}
579
580pub type IdEntry<'a, K, V> = hashbrown::hash_map::Entry<'a, K, V, BuildIdHasher>;
582
583pub type IdOccupiedEntry<'a, K, V> = hashbrown::hash_map::OccupiedEntry<'a, K, V, BuildIdHasher>;
585
586pub type IdVacantEntry<'a, K, V> = hashbrown::hash_map::VacantEntry<'a, K, V, BuildIdHasher>;
588
589#[derive(Default, Clone, Debug, Copy)]
591pub struct BuildIdHasher;
592impl BuildHasher for BuildIdHasher {
593 type Hasher = IdHasher;
594
595 fn build_hasher(&self) -> Self::Hasher {
596 IdHasher::default()
597 }
598}
599
600#[derive(Default)]
606pub struct IdHasher(u64);
607impl Hasher for IdHasher {
608 fn write(&mut self, _: &[u8]) {
609 unimplemented!("`only `write_u32` and `write_u64` are supported");
610 }
611
612 fn write_u32(&mut self, id: u32) {
613 self.0 = id as u64;
614 }
615
616 fn write_u64(&mut self, id: u64) {
617 self.0 = id;
618 }
619
620 fn finish(&self) -> u64 {
621 self.0
622 }
623}
624
625pub trait UniqueId: Clone + Copy + PartialEq + Eq + Hash {
627 fn new_unique() -> Self;
629}
630
631#[macro_export]
651macro_rules! static_id {
652 ($(
653 $(#[$attr:meta])*
654 $vis:vis static ref $IDENT:ident: $IdTy:ty;
655 )+) => {
656 $(
657 $crate::lazy_static! {
658 $(#[$attr])*
659 $vis static ref $IDENT: $IdTy = <$IdTy as $crate::UniqueId>::new_unique();
660 }
661 )+
662 };
663}