Skip to main content

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}