1use crate::Id;
2use core::hash::Hash;
3
4pub trait SnowflakeId: Id {
22 fn timestamp(&self) -> Self::Ty;
24
25 fn max_timestamp() -> Self::Ty;
27
28 fn machine_id(&self) -> Self::Ty;
30
31 fn max_machine_id() -> Self::Ty;
33
34 fn sequence(&self) -> Self::Ty;
36
37 fn max_sequence() -> Self::Ty;
39
40 #[must_use]
42 fn from_components(timestamp: Self::Ty, machine_id: Self::Ty, sequence: Self::Ty) -> Self;
43
44 fn has_sequence_room(&self) -> bool {
46 self.sequence() < Self::max_sequence()
47 }
48
49 fn next_sequence(&self) -> Self::Ty {
51 self.sequence() + Self::ONE
52 }
53
54 #[must_use]
56 fn increment_sequence(&self) -> Self {
57 Self::from_components(self.timestamp(), self.machine_id(), self.next_sequence())
58 }
59
60 #[must_use]
62 fn rollover_to_timestamp(&self, ts: Self::Ty) -> Self {
63 Self::from_components(ts, self.machine_id(), Self::ZERO)
64 }
65
66 fn is_valid(&self) -> bool;
69
70 #[must_use]
73 fn into_valid(self) -> Self;
74}
75
76#[cfg_attr(docsrs, doc(cfg(feature = "snowflake")))]
121#[macro_export]
122macro_rules! define_snowflake_id {
123 (
124 $(#[$meta:meta])*
125 $name:ident, $int:ty,
126 reserved: $reserved_bits:expr,
127 timestamp: $timestamp_bits:expr,
128 machine_id: $machine_bits:expr,
129 sequence: $sequence_bits:expr
130 ) => {
131 $(#[$meta])*
132 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
133 pub struct $name {
134 id: $int,
135 }
136
137 const _: () = {
138 assert!(
141 $reserved_bits + $timestamp_bits + $machine_bits + $sequence_bits == <$int>::BITS,
142 "Layout must match underlying type width"
143 );
144 };
145
146 impl $name {
147 pub const RESERVED_BITS: $int = $reserved_bits;
148 pub const TIMESTAMP_BITS: $int = $timestamp_bits;
149 pub const MACHINE_ID_BITS: $int = $machine_bits;
150 pub const SEQUENCE_BITS: $int = $sequence_bits;
151
152 pub const SEQUENCE_SHIFT: $int = 0;
153 pub const MACHINE_ID_SHIFT: $int = Self::SEQUENCE_SHIFT + Self::SEQUENCE_BITS;
154 pub const TIMESTAMP_SHIFT: $int = Self::MACHINE_ID_SHIFT + Self::MACHINE_ID_BITS;
155 pub const RESERVED_SHIFT: $int = Self::TIMESTAMP_SHIFT + Self::TIMESTAMP_BITS;
156
157 pub const RESERVED_MASK: $int = ((1 << Self::RESERVED_BITS) - 1);
158 pub const TIMESTAMP_MASK: $int = ((1 << Self::TIMESTAMP_BITS) - 1);
159 pub const MACHINE_ID_MASK: $int = ((1 << Self::MACHINE_ID_BITS) - 1);
160 pub const SEQUENCE_MASK: $int = ((1 << Self::SEQUENCE_BITS) - 1);
161
162 const fn valid_mask() -> $int {
163 (Self::TIMESTAMP_MASK << Self::TIMESTAMP_SHIFT) |
164 (Self::MACHINE_ID_MASK << Self::MACHINE_ID_SHIFT) |
165 (Self::SEQUENCE_MASK << Self::SEQUENCE_SHIFT)
166 }
167
168 #[must_use]
169 pub const fn from(timestamp: $int, machine_id: $int, sequence: $int) -> Self {
170 let t = (timestamp & Self::TIMESTAMP_MASK) << Self::TIMESTAMP_SHIFT;
171 let m = (machine_id & Self::MACHINE_ID_MASK) << Self::MACHINE_ID_SHIFT;
172 let s = (sequence & Self::SEQUENCE_MASK) << Self::SEQUENCE_SHIFT;
173 Self { id: t | m | s }
174 }
175
176 #[must_use]
178 pub const fn timestamp(&self) -> $int {
179 (self.id >> Self::TIMESTAMP_SHIFT) & Self::TIMESTAMP_MASK
180 }
181 #[must_use]
183 pub const fn machine_id(&self) -> $int {
184 (self.id >> Self::MACHINE_ID_SHIFT) & Self::MACHINE_ID_MASK
185 }
186 #[must_use]
188 pub const fn sequence(&self) -> $int {
189 (self.id >> Self::SEQUENCE_SHIFT) & Self::SEQUENCE_MASK
190 }
191 #[must_use]
194 pub const fn max_timestamp() -> $int {
195 (1 << Self::TIMESTAMP_BITS) - 1
196 }
197 #[must_use]
200 pub const fn max_machine_id() -> $int {
201 (1 << Self::MACHINE_ID_BITS) - 1
202 }
203 #[must_use]
206 pub const fn max_sequence() -> $int {
207 (1 << Self::SEQUENCE_BITS) - 1
208 }
209
210 #[must_use]
212 pub const fn to_raw(&self) -> $int {
213 self.id
214 }
215
216 #[must_use]
218 pub const fn from_raw(raw: $int) -> Self {
219 Self { id: raw }
220 }
221 }
222
223 impl $crate::Id for $name {
224 type Ty = $int;
225 const ZERO: $int = 0;
226 const ONE: $int = 1;
227
228 fn to_raw(&self) -> Self::Ty {
230 self.to_raw()
231 }
232
233 fn from_raw(raw: Self::Ty) -> Self {
235 Self::from_raw(raw)
236 }
237 }
238
239 impl $crate::SnowflakeId for $name {
240 fn timestamp(&self) -> Self::Ty {
241 self.timestamp()
242 }
243
244 fn machine_id(&self) -> Self::Ty {
245 self.machine_id()
246 }
247
248 fn sequence(&self) -> Self::Ty {
249 self.sequence()
250 }
251
252 fn max_timestamp() -> Self::Ty {
253 (1 << $timestamp_bits) - 1
254 }
255
256 fn max_machine_id() -> Self::Ty {
257 (1 << $machine_bits) - 1
258 }
259
260 fn max_sequence() -> Self::Ty {
261 (1 << $sequence_bits) - 1
262 }
263
264 fn from_components(timestamp: $int, machine_id: $int, sequence: $int) -> Self {
265 debug_assert!(timestamp <= Self::TIMESTAMP_MASK, "timestamp overflow");
266 debug_assert!(machine_id <= Self::MACHINE_ID_MASK, "machine_id overflow");
267 debug_assert!(sequence <= Self::SEQUENCE_MASK, "sequence overflow");
268 Self::from(timestamp, machine_id, sequence)
269 }
270
271 fn is_valid(&self) -> bool {
272 (self.to_raw() & !Self::valid_mask()) == 0
273 }
274
275 fn into_valid(self) -> Self {
276 let raw = self.to_raw() & Self::valid_mask();
277 Self::from_raw(raw)
278 }
279 }
280
281 $crate::cfg_base32! {
282 impl core::fmt::Display for $name {
283 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
284 use $crate::Base32SnowExt;
285 self.encode().fmt(f)
286 }
287 }
288
289 impl core::convert::TryFrom<&str> for $name {
290 type Error = $crate::Error<$name>;
291
292 fn try_from(s: &str) -> Result<Self, Self::Error> {
293 use $crate::Base32SnowExt;
294 Self::decode(s)
295 }
296 }
297
298 impl core::str::FromStr for $name {
299 type Err = $crate::Error<$name>;
300
301 fn from_str(s: &str) -> Result<Self, Self::Err> {
302 use $crate::Base32SnowExt;
303 Self::decode(s)
304 }
305 }
306 }
307
308 impl core::fmt::Debug for $name {
309 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310 let full = core::any::type_name::<Self>();
311 let name = full.rsplit("::").next().unwrap_or(full);
312 let mut dbg = f.debug_struct(name);
313 dbg.field("id", &format_args!("{:} (0x{:x})", self.to_raw(), self.to_raw()));
314 dbg.field("timestamp", &format_args!("{:} (0x{:x})", self.timestamp(), self.timestamp()));
315 dbg.field("machine_id", &format_args!("{:} (0x{:x})", self.machine_id(), self.machine_id()));
316 dbg.field("sequence", &format_args!("{:} (0x{:x})", self.sequence(), self.sequence()));
317 dbg.finish()
318 }
319 }
320 };
321}
322
323define_snowflake_id!(
324 SnowflakeTwitterId, u64,
340 reserved: 1,
341 timestamp: 41,
342 machine_id: 10,
343 sequence: 12
344);
345
346define_snowflake_id!(
347 SnowflakeDiscordId, u64,
362 reserved: 0,
363 timestamp: 42,
364 machine_id: 10,
365 sequence: 12
366);
367
368define_snowflake_id!(
369 SnowflakeMastodonId, u64,
383 reserved: 0,
384 timestamp: 48,
385 machine_id: 0,
386 sequence: 16
387);
388
389define_snowflake_id!(
390 SnowflakeInstagramId, u64,
405 reserved: 0,
406 timestamp: 41,
407 machine_id: 13,
408 sequence: 10
409);
410
411#[cfg(all(test, feature = "std"))]
412mod tests {
413 use super::*;
414 use std::println;
415
416 #[test]
417 fn test_snowflake_twitter_id_fields_and_bounds() {
418 let ts = SnowflakeTwitterId::max_timestamp();
419 let mid = SnowflakeTwitterId::max_machine_id();
420 let seq = SnowflakeTwitterId::max_sequence();
421
422 let id = SnowflakeTwitterId::from(ts, mid, seq);
423 println!("ID: {id:#?}");
424 assert_eq!(id.timestamp(), ts);
425 assert_eq!(id.machine_id(), mid);
426 assert_eq!(id.sequence(), seq);
427 assert_eq!(SnowflakeTwitterId::from_components(ts, mid, seq), id);
428 }
429
430 #[test]
431 fn test_snowflake_discord_id_fields_and_bounds() {
432 let ts = SnowflakeDiscordId::max_timestamp();
433 let mid = SnowflakeDiscordId::max_machine_id();
434 let seq = SnowflakeDiscordId::max_sequence();
435
436 let id = SnowflakeDiscordId::from(ts, mid, seq);
437 println!("ID: {id:#?}");
438 assert_eq!(id.timestamp(), ts);
439 assert_eq!(id.machine_id(), mid);
440 assert_eq!(id.sequence(), seq);
441 assert_eq!(SnowflakeDiscordId::from_components(ts, mid, seq), id);
442 }
443
444 #[test]
445 fn test_snowflake_mastodon_id_fields_and_bounds() {
446 let ts = SnowflakeMastodonId::max_timestamp();
447 let mid = SnowflakeMastodonId::max_machine_id();
448 let seq = SnowflakeMastodonId::max_sequence();
449
450 let id = SnowflakeMastodonId::from(ts, mid, seq);
451 println!("ID: {id:#?}");
452 assert_eq!(id.timestamp(), ts);
453 assert_eq!(id.machine_id(), 0); assert_eq!(id.sequence(), seq);
455 assert_eq!(SnowflakeMastodonId::from_components(ts, 0, seq), id);
456 }
457
458 #[test]
459 fn test_snowflake_instagram_id_fields_and_bounds() {
460 let ts = SnowflakeInstagramId::max_timestamp();
461 let mid = SnowflakeInstagramId::max_machine_id();
462 let seq = SnowflakeInstagramId::max_sequence();
463
464 let id = SnowflakeInstagramId::from(ts, mid, seq);
465 println!("ID: {id:#?}");
466 assert_eq!(id.timestamp(), ts);
467 assert_eq!(id.machine_id(), mid);
468 assert_eq!(id.sequence(), seq);
469 assert_eq!(SnowflakeInstagramId::from_components(ts, mid, seq), id);
470 }
471
472 #[test]
473 #[should_panic(expected = "timestamp overflow")]
474 fn twitter_timestamp_overflow_panics() {
475 let ts = SnowflakeTwitterId::max_timestamp() + 1;
476 let _ = SnowflakeTwitterId::from_components(ts, 0, 0);
477 }
478
479 #[test]
480 #[should_panic(expected = "machine_id overflow")]
481 fn twitter_machine_id_overflow_panics() {
482 let mid = SnowflakeTwitterId::max_machine_id() + 1;
483 let _ = SnowflakeTwitterId::from_components(0, mid, 0);
484 }
485
486 #[test]
487 #[should_panic(expected = "sequence overflow")]
488 fn twitter_sequence_overflow_panics() {
489 let seq = SnowflakeTwitterId::max_sequence() + 1;
490 let _ = SnowflakeTwitterId::from_components(0, 0, seq);
491 }
492
493 #[test]
494 #[should_panic(expected = "timestamp overflow")]
495 fn discord_timestamp_overflow_panics() {
496 let ts = SnowflakeDiscordId::max_timestamp() + 1;
497 let _ = SnowflakeDiscordId::from_components(ts, 0, 0);
498 }
499
500 #[test]
501 #[should_panic(expected = "machine_id overflow")]
502 fn discord_machine_id_overflow_panics() {
503 let mid = SnowflakeDiscordId::max_machine_id() + 1;
504 let _ = SnowflakeDiscordId::from_components(0, mid, 0);
505 }
506
507 #[test]
508 #[should_panic(expected = "sequence overflow")]
509 fn discord_sequence_overflow_panics() {
510 let seq = SnowflakeDiscordId::max_sequence() + 1;
511 let _ = SnowflakeDiscordId::from_components(0, 0, seq);
512 }
513
514 #[test]
515 #[should_panic(expected = "timestamp overflow")]
516 fn mastodon_timestamp_overflow_panics() {
517 let ts = SnowflakeMastodonId::max_timestamp() + 1;
518 let _ = SnowflakeMastodonId::from_components(ts, 0, 0);
519 }
520
521 #[test]
522 #[should_panic(expected = "machine_id overflow")]
523 fn mastodon_machine_id_overflow_panics() {
524 let mid = SnowflakeMastodonId::max_machine_id() + 1;
525 let _ = SnowflakeMastodonId::from_components(0, mid, 0);
526 }
527
528 #[test]
529 #[should_panic(expected = "sequence overflow")]
530 fn mastodon_sequence_overflow_panics() {
531 let seq = SnowflakeMastodonId::max_sequence() + 1;
532 let _ = SnowflakeMastodonId::from_components(0, 0, seq);
533 }
534
535 #[test]
536 #[should_panic(expected = "timestamp overflow")]
537 fn instagram_timestamp_overflow_panics() {
538 let ts = SnowflakeInstagramId::max_timestamp() + 1;
539 let _ = SnowflakeInstagramId::from_components(ts, 0, 0);
540 }
541
542 #[test]
543 #[should_panic(expected = "machine_id overflow")]
544 fn instagram_machine_id_overflow_panics() {
545 let mid = SnowflakeInstagramId::max_machine_id() + 1;
546 let _ = SnowflakeInstagramId::from_components(0, mid, 0);
547 }
548
549 #[test]
550 #[should_panic(expected = "sequence overflow")]
551 fn instagram_sequence_overflow_panics() {
552 let seq = SnowflakeInstagramId::max_sequence() + 1;
553 let _ = SnowflakeInstagramId::from_components(0, 0, seq);
554 }
555
556 #[test]
557 fn twitter_validity() {
558 let id = SnowflakeTwitterId::from_raw(u64::MAX);
559 assert!(!id.is_valid()); let valid = id.into_valid();
561 assert!(valid.is_valid());
562 }
563
564 #[test]
565 fn instagram_validity() {
566 let id = SnowflakeInstagramId::from_raw(u64::MAX);
567 assert!(id.is_valid());
568 let valid = id.into_valid();
569 assert!(valid.is_valid());
570 }
571
572 #[test]
573 fn discord_validity() {
574 let id = SnowflakeDiscordId::from_raw(u64::MAX);
575 assert!(id.is_valid());
576 let valid = id.into_valid();
577 assert!(valid.is_valid());
578 }
579
580 #[test]
581 fn mastodon_validity() {
582 let id = SnowflakeMastodonId::from_raw(u64::MAX);
583 assert!(id.is_valid());
584 let valid = id.into_valid();
585 assert!(valid.is_valid());
586 }
587
588 #[test]
589 fn twitter_low_bit_fields() {
590 let id = SnowflakeTwitterId::from_components(0, 0, 0);
591 assert_eq!(id.timestamp(), 0);
592 assert_eq!(id.machine_id(), 0);
593 assert_eq!(id.sequence(), 0);
594
595 let id = SnowflakeTwitterId::from_components(1, 1, 1);
596 assert_eq!(id.timestamp(), 1);
597 assert_eq!(id.machine_id(), 1);
598 assert_eq!(id.sequence(), 1);
599 }
600
601 #[test]
602 fn discord_low_bit_fields() {
603 let id = SnowflakeDiscordId::from_components(0, 0, 0);
604 assert_eq!(id.timestamp(), 0);
605 assert_eq!(id.machine_id(), 0);
606 assert_eq!(id.sequence(), 0);
607
608 let id = SnowflakeDiscordId::from_components(1, 1, 1);
609 assert_eq!(id.timestamp(), 1);
610 assert_eq!(id.machine_id(), 1);
611 assert_eq!(id.sequence(), 1);
612 }
613
614 #[test]
615 fn mastodon_low_bit_fields() {
616 let id = SnowflakeMastodonId::from_components(0, 0, 0);
617 assert_eq!(id.timestamp(), 0);
618 assert_eq!(id.machine_id(), 0);
619 assert_eq!(id.sequence(), 0);
620
621 let id = SnowflakeMastodonId::from_components(1, 0, 1);
622 assert_eq!(id.timestamp(), 1);
623 assert_eq!(id.machine_id(), 0); assert_eq!(id.sequence(), 1);
625 }
626
627 #[test]
628 fn instagram_low_bit_fields() {
629 let id = SnowflakeInstagramId::from_components(0, 0, 0);
630 assert_eq!(id.timestamp(), 0);
631 assert_eq!(id.machine_id(), 0);
632 assert_eq!(id.sequence(), 0);
633
634 let id = SnowflakeInstagramId::from_components(1, 1, 1);
635 assert_eq!(id.timestamp(), 1);
636 assert_eq!(id.machine_id(), 1);
637 assert_eq!(id.sequence(), 1);
638 }
639
640 #[test]
641 fn twitter_edge_rollover() {
642 let id = SnowflakeTwitterId::from_components(0, 0, SnowflakeTwitterId::max_sequence());
643 assert_eq!(id.sequence(), SnowflakeTwitterId::max_sequence());
644
645 let id = SnowflakeTwitterId::from_components(0, SnowflakeTwitterId::max_machine_id(), 0);
646 assert_eq!(id.machine_id(), SnowflakeTwitterId::max_machine_id());
647 }
648
649 #[test]
650 fn discord_edge_rollover() {
651 let id = SnowflakeDiscordId::from_components(0, 0, SnowflakeDiscordId::max_sequence());
652 assert_eq!(id.sequence(), SnowflakeDiscordId::max_sequence());
653
654 let id = SnowflakeDiscordId::from_components(0, SnowflakeDiscordId::max_machine_id(), 0);
655 assert_eq!(id.machine_id(), SnowflakeDiscordId::max_machine_id());
656 }
657
658 #[test]
659 fn mastodon_edge_rollover() {
660 let id = SnowflakeMastodonId::from_components(0, 0, SnowflakeMastodonId::max_sequence());
661 assert_eq!(id.sequence(), SnowflakeMastodonId::max_sequence());
662 }
663
664 #[test]
665 fn instagram_edge_rollover() {
666 let id = SnowflakeInstagramId::from_components(0, 0, SnowflakeInstagramId::max_sequence());
667 assert_eq!(id.sequence(), SnowflakeInstagramId::max_sequence());
668
669 let id =
670 SnowflakeInstagramId::from_components(0, SnowflakeInstagramId::max_machine_id(), 0);
671 assert_eq!(id.machine_id(), SnowflakeInstagramId::max_machine_id());
672 }
673}