snowflake_gen/generator/creation.rs
1use std::time::{SystemTime, UNIX_EPOCH};
2use crate::error::SnowflakeError;
3use crate::layout::BitLayout;
4use crate::utils::get_time_millis;
5use crate::generator::SnowflakeIdGenerator;
6
7impl SnowflakeIdGenerator {
8 /// Constructs a generator using the UNIX epoch and the default [`BitLayout`].
9 ///
10 /// ```rust
11 /// use snowflake_gen::SnowflakeIdGenerator;
12 ///
13 /// let mut idgen = SnowflakeIdGenerator::new(1, 1).unwrap();
14 /// ```
15 pub fn new(machine_id: i64, node_id: i64) -> Result<Self, SnowflakeError> {
16 Self::with_epoch(machine_id, node_id, UNIX_EPOCH)
17 }
18
19 /// Constructs a generator using a custom epoch and the default [`BitLayout`].
20 ///
21 /// ```rust
22 /// use std::time::{Duration, UNIX_EPOCH};
23 /// use snowflake_gen::SnowflakeIdGenerator;
24 ///
25 /// // Discord epoch: 1 January 2015 00:00:00 UTC
26 /// let discord_epoch = UNIX_EPOCH + Duration::from_millis(1_420_070_400_000);
27 /// let mut idgen = SnowflakeIdGenerator::with_epoch(1, 1, discord_epoch).unwrap();
28 /// ```
29 pub fn with_epoch(
30 machine_id: i64,
31 node_id: i64,
32 epoch: SystemTime,
33 ) -> Result<Self, SnowflakeError> {
34 Self::with_layout_and_epoch(machine_id, node_id, BitLayout::default(), epoch)
35 }
36
37 /// Constructs a generator with a fully custom [`BitLayout`] and UNIX epoch.
38 ///
39 /// ```rust
40 /// use snowflake_gen::{BitLayout, SnowflakeIdGenerator};
41 ///
42 /// let layout = BitLayout::new(38, 8, 7, 10).unwrap();
43 /// let mut idgen = SnowflakeIdGenerator::with_layout(1, 1, layout).unwrap();
44 /// ```
45 pub fn with_layout(
46 machine_id: i64,
47 node_id: i64,
48 layout: BitLayout,
49 ) -> Result<Self, SnowflakeError> {
50 Self::with_layout_and_epoch(machine_id, node_id, layout, UNIX_EPOCH)
51 }
52
53 /// Constructs a generator with a fully custom [`BitLayout`] and epoch.
54 ///
55 /// # Errors
56 ///
57 /// - [`SnowflakeError::MachineIdOutOfRange`] if `machine_id > layout.max_machine_id()`.
58 /// - [`SnowflakeError::NodeIdOutOfRange`] if `node_id > layout.max_node_id()`.
59 /// - [`SnowflakeError::ClockBeforeEpoch`] if the current time is before `epoch`.
60 pub fn with_layout_and_epoch(
61 machine_id: i64,
62 node_id: i64,
63 layout: BitLayout,
64 epoch: SystemTime,
65 ) -> Result<Self, SnowflakeError> {
66 if machine_id < 0 || machine_id > layout.max_machine_id() {
67 return Err(SnowflakeError::MachineIdOutOfRange {
68 given: machine_id,
69 max: layout.max_machine_id(),
70 });
71 }
72 if node_id < 0 || node_id > layout.max_node_id() {
73 return Err(SnowflakeError::NodeIdOutOfRange {
74 given: node_id,
75 max: layout.max_node_id(),
76 });
77 }
78
79 let last_time_millis = get_time_millis(epoch)?;
80
81 Ok(Self {
82 epoch,
83 last_time_millis,
84 machine_id,
85 node_id,
86 idx: 0,
87 layout,
88 })
89 }
90}