1use crate::{Error, Result};
2use core::fmt;
3use std::{
4 hash::Hash,
5 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
6};
7
8pub trait ToU64 {
15 fn to_u64(self) -> Result<u64>;
16}
17
18impl ToU64 for u8 {
19 fn to_u64(self) -> Result<u64> {
20 Ok(self as u64)
21 }
22}
23
24impl ToU64 for u16 {
25 fn to_u64(self) -> Result<u64> {
26 Ok(self as u64)
27 }
28}
29
30impl ToU64 for u32 {
31 fn to_u64(self) -> Result<u64> {
32 Ok(self as u64)
33 }
34}
35
36impl ToU64 for u64 {
37 fn to_u64(self) -> Result<u64> {
38 Ok(self)
39 }
40}
41
42impl ToU64 for u128 {
43 fn to_u64(self) -> Result<u64> {
44 self.try_into().map_err(|_| Error::FailedToU64)
45 }
46}
47
48pub trait Snowflake:
66 Sized + Copy + Clone + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash
67{
68 type Ty: Copy
70 + Clone
71 + Add<Output = Self::Ty>
72 + AddAssign
73 + Sub<Output = Self::Ty>
74 + SubAssign
75 + Mul<Output = Self::Ty>
76 + MulAssign
77 + Div<Output = Self::Ty>
78 + DivAssign
79 + Into<Self::Ty>
80 + From<Self::Ty>
81 + Ord
82 + PartialOrd
83 + Eq
84 + PartialEq
85 + Hash
86 + ToU64
87 + fmt::Debug
88 + fmt::Display;
89
90 const ZERO: Self::Ty;
92
93 const ONE: Self::Ty;
95
96 fn timestamp(&self) -> Self::Ty;
98
99 fn max_timestamp() -> Self::Ty;
101
102 fn machine_id(&self) -> Self::Ty;
104
105 fn max_machine_id() -> Self::Ty;
107
108 fn sequence(&self) -> Self::Ty;
110
111 fn max_sequence() -> Self::Ty;
113
114 fn from_components(timestamp: Self::Ty, machine_id: Self::Ty, sequence: Self::Ty) -> Self;
116
117 fn to_raw(&self) -> Self::Ty;
119
120 fn from_raw(raw: Self::Ty) -> Self;
122
123 fn has_sequence_room(&self) -> bool {
125 self.sequence() < Self::max_sequence()
126 }
127
128 fn next_sequence(&self) -> Self::Ty {
130 self.sequence() + Self::ONE
131 }
132
133 fn increment_sequence(&self) -> Self {
135 Self::from_components(self.timestamp(), self.machine_id(), self.next_sequence())
136 }
137
138 fn rollover_to_timestamp(&self, ts: Self::Ty) -> Self {
140 Self::from_components(ts, self.machine_id(), Self::ZERO)
141 }
142
143 fn to_padded_string(&self) -> String;
144}
145
146#[macro_export]
194macro_rules! define_snowflake_id {
195 (
196 $(#[$meta:meta])*
197 $name:ident, $int:ty,
198 reserved: $reserved_bits:expr,
199 timestamp: $timestamp_bits:expr,
200 machine_id: $machine_bits:expr,
201 sequence: $sequence_bits:expr
202 ) => {
203 $(#[$meta])*
204 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
205 pub struct $name {
206 id: $int,
207 }
208
209 const _: () = {
210 assert!(
213 $reserved_bits + $timestamp_bits + $machine_bits + $sequence_bits == <$int>::BITS,
214 "Snowflake layout overflows the underlying integer type"
215 );
216 };
217
218 impl $name {
219 pub const RESERVED_BITS: $int = $reserved_bits;
220 pub const TIMESTAMP_BITS: $int = $timestamp_bits;
221 pub const MACHINE_ID_BITS: $int = $machine_bits;
222 pub const SEQUENCE_BITS: $int = $sequence_bits;
223
224 pub const SEQUENCE_SHIFT: $int = 0;
225 pub const MACHINE_ID_SHIFT: $int = Self::SEQUENCE_SHIFT + Self::SEQUENCE_BITS;
226 pub const TIMESTAMP_SHIFT: $int = Self::MACHINE_ID_SHIFT + Self::MACHINE_ID_BITS;
227 pub const RESERVED_SHIFT: $int = Self::TIMESTAMP_SHIFT + Self::TIMESTAMP_BITS;
228
229 pub const RESERVED_MASK: $int = ((1 << Self::RESERVED_BITS) - 1);
230 pub const TIMESTAMP_MASK: $int = ((1 << Self::TIMESTAMP_BITS) - 1);
231 pub const MACHINE_ID_MASK: $int = ((1 << Self::MACHINE_ID_BITS) - 1);
232 pub const SEQUENCE_MASK: $int = ((1 << Self::SEQUENCE_BITS) - 1);
233
234 pub const fn from(timestamp: $int, machine_id: $int, sequence: $int) -> Self {
235 let t = (timestamp & Self::TIMESTAMP_MASK) << Self::TIMESTAMP_SHIFT;
236 let m = (machine_id & Self::MACHINE_ID_MASK) << Self::MACHINE_ID_SHIFT;
237 let s = (sequence & Self::SEQUENCE_MASK) << Self::SEQUENCE_SHIFT;
238 Self { id: t | m | s }
239 }
240
241 pub const fn timestamp(&self) -> $int {
243 (self.id >> Self::TIMESTAMP_SHIFT) & Self::TIMESTAMP_MASK
244 }
245 pub const fn machine_id(&self) -> $int {
247 (self.id >> Self::MACHINE_ID_SHIFT) & Self::MACHINE_ID_MASK
248 }
249 pub const fn sequence(&self) -> $int {
251 (self.id >> Self::SEQUENCE_SHIFT) & Self::SEQUENCE_MASK
252 }
253 }
254
255 impl $crate::Snowflake for $name {
256 type Ty = $int;
257
258 const ZERO: $int = 0;
259 const ONE: $int = 1;
260
261 fn timestamp(&self) -> Self::Ty {
262 self.timestamp()
263 }
264
265 fn machine_id(&self) -> Self::Ty {
266 self.machine_id()
267 }
268
269 fn sequence(&self) -> Self::Ty {
270 self.sequence()
271 }
272
273 fn max_timestamp() -> Self::Ty {
274 (1 << $timestamp_bits) - 1
275 }
276
277 fn max_machine_id() -> Self::Ty {
278 (1 << $machine_bits) - 1
279 }
280
281 fn max_sequence() -> Self::Ty {
282 (1 << $sequence_bits) - 1
283 }
284
285 fn from_components(timestamp: $int, machine_id: $int, sequence: $int) -> Self {
286 debug_assert!(timestamp <= Self::TIMESTAMP_MASK, "timestamp overflow");
287 debug_assert!(machine_id <= Self::MACHINE_ID_MASK, "machine_id overflow");
288 debug_assert!(sequence <= Self::SEQUENCE_MASK, "sequence overflow");
289 Self::from(timestamp, machine_id, sequence)
290 }
291
292 fn to_raw(&self) -> Self::Ty {
293 self.id
294 }
295
296 fn from_raw(raw: Self::Ty) -> Self {
297 Self { id: raw }
298 }
299
300 fn to_padded_string(&self) -> String {
301 let max = Self::Ty::MAX;
302 let mut n = max;
303 let mut digits = 1;
304 while n >= 10 {
305 n = n / 10;
306 digits += 1;
307 }
308 format!("{:0width$}", self.to_raw(), width = digits)
309 }
310 }
311
312 impl core::fmt::Display for $name {
313 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
314 write!(f, "{}", self.id)
315 }
316 }
317
318 impl core::fmt::Debug for $name {
319 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
320 let full = core::any::type_name::<Self>();
321 let name = full.rsplit("::").next().unwrap_or(full);
322 let mut dbg = f.debug_struct(name);
323 dbg.field("id", &format_args!("{:} (0x{:x})", self.to_raw(), self.to_raw()));
324
325 use $crate::Snowflake;
326 dbg.field("padded", &self.to_padded_string());
327
328 #[cfg(feature = "base32")]
329 {
330 use $crate::SnowflakeBase32Ext;
331 dbg.field("base32", &self.encode());
332 }
333
334 dbg.field("timestamp", &format_args!("{:} (0x{:x})", self.timestamp(), self.timestamp()));
335 dbg.field("machine_id", &format_args!("{:} (0x{:x})", self.machine_id(), self.machine_id()));
336 dbg.field("sequence", &format_args!("{:} (0x{:x})", self.sequence(), self.sequence()));
337
338 dbg.finish()
339 }
340 }
341 };
342}
343
344define_snowflake_id!(
345 SnowflakeTwitterId, u64,
361 reserved: 1,
362 timestamp: 41,
363 machine_id: 10,
364 sequence: 12
365);
366
367define_snowflake_id!(
368 SnowflakeDiscordId, u64,
383 reserved: 0,
384 timestamp: 42,
385 machine_id: 10,
386 sequence: 12
387);
388
389define_snowflake_id!(
390 SnowflakeMastodonId, u64,
404 reserved: 0,
405 timestamp: 48,
406 machine_id: 0,
407 sequence: 16
408);
409
410define_snowflake_id!(
411 SnowflakeInstagramId, u64,
426 reserved: 0,
427 timestamp: 41,
428 machine_id: 13,
429 sequence: 10
430);
431
432define_snowflake_id!(
433 SnowflakeLongId, u128,
450 reserved: 40,
451 timestamp: 48,
452 machine_id: 20,
453 sequence: 20
454);
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
461 fn test_snowflake_twitter_id_fields_and_bounds() {
462 let ts = SnowflakeTwitterId::max_timestamp();
463 let mid = SnowflakeTwitterId::max_machine_id();
464 let seq = SnowflakeTwitterId::max_sequence();
465
466 let id = SnowflakeTwitterId::from(ts, mid, seq);
467 println!("ID: {:#?}", id);
468 assert_eq!(id.timestamp(), ts);
469 assert_eq!(id.machine_id(), mid);
470 assert_eq!(id.sequence(), seq);
471 assert_eq!(SnowflakeTwitterId::from_components(ts, mid, seq), id);
472 }
473
474 #[test]
475 fn test_snowflake_discord_id_fields_and_bounds() {
476 let ts = SnowflakeDiscordId::max_timestamp();
477 let mid = SnowflakeDiscordId::max_machine_id();
478 let seq = SnowflakeDiscordId::max_sequence();
479
480 let id = SnowflakeDiscordId::from(ts, mid, seq);
481 println!("ID: {:#?}", id);
482 assert_eq!(id.timestamp(), ts);
483 assert_eq!(id.machine_id(), mid);
484 assert_eq!(id.sequence(), seq);
485 assert_eq!(SnowflakeDiscordId::from_components(ts, mid, seq), id);
486 }
487
488 #[test]
489 fn test_snowflake_mastodon_id_fields_and_bounds() {
490 let ts = SnowflakeMastodonId::max_timestamp();
491 let mid = SnowflakeMastodonId::max_machine_id();
492 let seq = SnowflakeMastodonId::max_sequence();
493
494 let id = SnowflakeMastodonId::from(ts, mid, seq);
495 println!("ID: {:#?}", id);
496 assert_eq!(id.timestamp(), ts);
497 assert_eq!(id.machine_id(), 0); assert_eq!(id.sequence(), seq);
499 assert_eq!(SnowflakeMastodonId::from_components(ts, 0, seq), id);
500 }
501
502 #[test]
503 fn test_snowflake_instagram_id_fields_and_bounds() {
504 let ts = SnowflakeInstagramId::max_timestamp();
505 let mid = SnowflakeInstagramId::max_machine_id();
506 let seq = SnowflakeInstagramId::max_sequence();
507
508 let id = SnowflakeInstagramId::from(ts, mid, seq);
509 println!("ID: {:#?}", id);
510 assert_eq!(id.timestamp(), ts);
511 assert_eq!(id.machine_id(), mid);
512 assert_eq!(id.sequence(), seq);
513 assert_eq!(SnowflakeInstagramId::from_components(ts, mid, seq), id);
514 }
515
516 #[test]
517 fn test_snowflake_long_id_fields_and_bounds() {
518 let ts = SnowflakeLongId::max_timestamp();
519 let mid = SnowflakeLongId::max_machine_id();
520 let seq = SnowflakeLongId::max_sequence();
521
522 let id = SnowflakeLongId::from(ts, mid, seq);
523 println!("ID: {:#?}", id);
524 assert_eq!(id.timestamp(), ts);
525 assert_eq!(id.machine_id(), mid);
526 assert_eq!(id.sequence(), seq);
527 assert_eq!(SnowflakeLongId::from_components(ts, mid, seq), id);
528 }
529
530 #[test]
531 #[should_panic(expected = "timestamp overflow")]
532 fn twitter_timestamp_overflow_panics() {
533 let ts = SnowflakeTwitterId::max_timestamp() + 1;
534 SnowflakeTwitterId::from_components(ts, 0, 0);
535 }
536
537 #[test]
538 #[should_panic(expected = "machine_id overflow")]
539 fn twitter_machine_id_overflow_panics() {
540 let mid = SnowflakeTwitterId::max_machine_id() + 1;
541 SnowflakeTwitterId::from_components(0, mid, 0);
542 }
543
544 #[test]
545 #[should_panic(expected = "sequence overflow")]
546 fn twitter_sequence_overflow_panics() {
547 let seq = SnowflakeTwitterId::max_sequence() + 1;
548 SnowflakeTwitterId::from_components(0, 0, seq);
549 }
550
551 #[test]
552 #[should_panic(expected = "timestamp overflow")]
553 fn discord_timestamp_overflow_panics() {
554 let ts = SnowflakeDiscordId::max_timestamp() + 1;
555 SnowflakeDiscordId::from_components(ts, 0, 0);
556 }
557
558 #[test]
559 #[should_panic(expected = "machine_id overflow")]
560 fn discord_machine_id_overflow_panics() {
561 let mid = SnowflakeDiscordId::max_machine_id() + 1;
562 SnowflakeDiscordId::from_components(0, mid, 0);
563 }
564
565 #[test]
566 #[should_panic(expected = "sequence overflow")]
567 fn discord_sequence_overflow_panics() {
568 let seq = SnowflakeDiscordId::max_sequence() + 1;
569 SnowflakeDiscordId::from_components(0, 0, seq);
570 }
571
572 #[test]
573 #[should_panic(expected = "timestamp overflow")]
574 fn mastodon_timestamp_overflow_panics() {
575 let ts = SnowflakeMastodonId::max_timestamp() + 1;
576 SnowflakeMastodonId::from_components(ts, 0, 0);
577 }
578
579 #[test]
580 #[should_panic(expected = "machine_id overflow")]
581 fn mastodon_machine_id_overflow_panics() {
582 let mid = SnowflakeMastodonId::max_machine_id() + 1;
583 SnowflakeMastodonId::from_components(0, mid, 0);
584 }
585
586 #[test]
587 #[should_panic(expected = "sequence overflow")]
588 fn mastodon_sequence_overflow_panics() {
589 let seq = SnowflakeMastodonId::max_sequence() + 1;
590 SnowflakeMastodonId::from_components(0, 0, seq);
591 }
592
593 #[test]
594 #[should_panic(expected = "timestamp overflow")]
595 fn instagram_timestamp_overflow_panics() {
596 let ts = SnowflakeInstagramId::max_timestamp() + 1;
597 SnowflakeInstagramId::from_components(ts, 0, 0);
598 }
599
600 #[test]
601 #[should_panic(expected = "machine_id overflow")]
602 fn instagram_machine_id_overflow_panics() {
603 let mid = SnowflakeInstagramId::max_machine_id() + 1;
604 SnowflakeInstagramId::from_components(0, mid, 0);
605 }
606
607 #[test]
608 #[should_panic(expected = "sequence overflow")]
609 fn instagram_sequence_overflow_panics() {
610 let seq = SnowflakeInstagramId::max_sequence() + 1;
611 SnowflakeInstagramId::from_components(0, 0, seq);
612 }
613
614 #[test]
615 #[should_panic(expected = "timestamp overflow")]
616 fn long_timestamp_overflow_panics() {
617 let ts = SnowflakeLongId::max_timestamp() + 1;
618 SnowflakeLongId::from_components(ts, 0, 0);
619 }
620
621 #[test]
622 #[should_panic(expected = "machine_id overflow")]
623 fn long_machine_id_overflow_panics() {
624 let mid = SnowflakeLongId::max_machine_id() + 1;
625 SnowflakeLongId::from_components(0, mid, 0);
626 }
627
628 #[test]
629 #[should_panic(expected = "sequence overflow")]
630 fn long_sequence_overflow_panics() {
631 let seq = SnowflakeLongId::max_sequence() + 1;
632 SnowflakeLongId::from_components(0, 0, seq);
633 }
634
635 #[test]
636 fn twitter_low_bit_fields() {
637 let id = SnowflakeTwitterId::from_components(0, 0, 0);
638 assert_eq!(id.timestamp(), 0);
639 assert_eq!(id.machine_id(), 0);
640 assert_eq!(id.sequence(), 0);
641
642 let id = SnowflakeTwitterId::from_components(1, 1, 1);
643 assert_eq!(id.timestamp(), 1);
644 assert_eq!(id.machine_id(), 1);
645 assert_eq!(id.sequence(), 1);
646 }
647
648 #[test]
649 fn discord_low_bit_fields() {
650 let id = SnowflakeDiscordId::from_components(0, 0, 0);
651 assert_eq!(id.timestamp(), 0);
652 assert_eq!(id.machine_id(), 0);
653 assert_eq!(id.sequence(), 0);
654
655 let id = SnowflakeDiscordId::from_components(1, 1, 1);
656 assert_eq!(id.timestamp(), 1);
657 assert_eq!(id.machine_id(), 1);
658 assert_eq!(id.sequence(), 1);
659 }
660
661 #[test]
662 fn mastodon_low_bit_fields() {
663 let id = SnowflakeMastodonId::from_components(0, 0, 0);
664 assert_eq!(id.timestamp(), 0);
665 assert_eq!(id.machine_id(), 0);
666 assert_eq!(id.sequence(), 0);
667
668 let id = SnowflakeMastodonId::from_components(1, 0, 1);
669 assert_eq!(id.timestamp(), 1);
670 assert_eq!(id.machine_id(), 0); assert_eq!(id.sequence(), 1);
672 }
673
674 #[test]
675 fn instagram_low_bit_fields() {
676 let id = SnowflakeInstagramId::from_components(0, 0, 0);
677 assert_eq!(id.timestamp(), 0);
678 assert_eq!(id.machine_id(), 0);
679 assert_eq!(id.sequence(), 0);
680
681 let id = SnowflakeInstagramId::from_components(1, 1, 1);
682 assert_eq!(id.timestamp(), 1);
683 assert_eq!(id.machine_id(), 1);
684 assert_eq!(id.sequence(), 1);
685 }
686
687 #[test]
688 fn long_low_bit_fields() {
689 let id = SnowflakeLongId::from_components(0, 0, 0);
690 assert_eq!(id.timestamp(), 0);
691 assert_eq!(id.machine_id(), 0);
692 assert_eq!(id.sequence(), 0);
693
694 let id = SnowflakeLongId::from_components(1, 1, 1);
695 assert_eq!(id.timestamp(), 1);
696 assert_eq!(id.machine_id(), 1);
697 assert_eq!(id.sequence(), 1);
698 }
699
700 #[test]
701 fn twitter_edge_rollover() {
702 let id = SnowflakeTwitterId::from_components(0, 0, SnowflakeTwitterId::max_sequence());
703 assert_eq!(id.sequence(), SnowflakeTwitterId::max_sequence());
704
705 let id = SnowflakeTwitterId::from_components(0, SnowflakeTwitterId::max_machine_id(), 0);
706 assert_eq!(id.machine_id(), SnowflakeTwitterId::max_machine_id());
707 }
708
709 #[test]
710 fn discord_edge_rollover() {
711 let id = SnowflakeDiscordId::from_components(0, 0, SnowflakeDiscordId::max_sequence());
712 assert_eq!(id.sequence(), SnowflakeDiscordId::max_sequence());
713
714 let id = SnowflakeDiscordId::from_components(0, SnowflakeDiscordId::max_machine_id(), 0);
715 assert_eq!(id.machine_id(), SnowflakeDiscordId::max_machine_id());
716 }
717
718 #[test]
719 fn mastodon_edge_rollover() {
720 let id = SnowflakeMastodonId::from_components(0, 0, SnowflakeMastodonId::max_sequence());
721 assert_eq!(id.sequence(), SnowflakeMastodonId::max_sequence());
722 }
723
724 #[test]
725 fn instagram_edge_rollover() {
726 let id = SnowflakeInstagramId::from_components(0, 0, SnowflakeInstagramId::max_sequence());
727 assert_eq!(id.sequence(), SnowflakeInstagramId::max_sequence());
728
729 let id =
730 SnowflakeInstagramId::from_components(0, SnowflakeInstagramId::max_machine_id(), 0);
731 assert_eq!(id.machine_id(), SnowflakeInstagramId::max_machine_id());
732 }
733
734 #[test]
735 fn long_edge_rollover() {
736 let id = SnowflakeLongId::from_components(0, 0, SnowflakeLongId::max_sequence());
737 assert_eq!(id.sequence(), SnowflakeLongId::max_sequence());
738
739 let id = SnowflakeLongId::from_components(0, SnowflakeLongId::max_machine_id(), 0);
740 assert_eq!(id.machine_id(), SnowflakeLongId::max_machine_id());
741 }
742}