rx_rust/utils/id_generator.rs
1//! Ids handed out under a lock, to tell one thing apart from another that replaced it.
2//!
3//! Two shapes use this, and the difference lives in the caller, not in the id:
4//!
5//! - a *generation*, compared against [`IdGenerator::latest`] to tell whether something built with
6//! the lock released is still the current one — see
7//! [`SharedDisposal`](crate::disposable::shared_disposal::SharedDisposal) and
8//! [`Switch`](crate::operators::combining::switch::Switch);
9//! - a *key*, identifying an entry of a collection — see
10//! [`MergeAll`](crate::operators::combining::merge_all::MergeAll) and
11//! [`PublishSubject`](crate::subject::publish_subject::PublishSubject).
12//!
13//! An [`Id`] can only come from an [`IdGenerator`], which never hands the same one out twice, so a
14//! holder of an id cannot forge one that collides with a later value.
15
16/// Hands out an [`Id`] that is never equal to any it handed out before.
17///
18/// It carries no lock of its own: it lives inside state that is already guarded, and
19/// [`next_id`](Self::next_id) takes `&mut self`.
20#[derive(Debug, Default)]
21pub struct IdGenerator(u64);
22
23/// An id handed out by an [`IdGenerator`].
24///
25/// There is deliberately no `Default`: an id can only be obtained from a generator, so it can
26/// never accidentally equal the value a generator starts from.
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct Id(u64);
29
30impl IdGenerator {
31 /// The next id, greater than every id handed out before.
32 ///
33 /// `u64` is big enough that this never wraps on any platform.
34 #[must_use = "the id identifies what is being handed out, and is the only way to recognize it later"]
35 pub fn next_id(&mut self) -> Id {
36 self.0 += 1;
37 Id(self.0)
38 }
39
40 /// The id handed out last, or `None` before the first one.
41 pub fn latest(&self) -> Option<Id> {
42 (self.0 != 0).then_some(Id(self.0))
43 }
44}