1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use std::time::{SystemTime, UNIX_EPOCH};

use crate::{const_panic_new, INSTANCE_MAX};

/// A builder for a snowflake Generator. This builder can be used for both [`Generator`] and
/// [`sync::Generator`].
///
/// [`Generator`]: crate::Generator
/// [`sync::Generator`]: crate::sync::Generator
#[derive(Copy, Clone, Debug)]
pub struct Builder {
    pub(crate) instance: u16,
    pub(crate) epoch: SystemTime,
}

impl Builder {
    /// Creates a new `Builder` with the instance set to `0` and epoch set to [`UNIX_EPOCH`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::time::UNIX_EPOCH;
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let generator: Generator = Builder::new().build();
    ///
    /// assert_eq!(generator.instance(), 0);
    /// assert_eq!(generator.epoch(), UNIX_EPOCH);
    /// ```
    #[inline]
    pub const fn new() -> Self {
        Self {
            instance: 0,
            epoch: UNIX_EPOCH,
        }
    }

    /// Sets the `instance` value of the `Builder`.
    ///
    /// # Panics
    ///
    /// Panics if the provided `instance` exceeds the maximum value (2^10 -1).
    ///
    /// # Examples
    ///
    /// ```
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let generator: Generator = Builder::new().instance(400).build();
    ///
    /// assert_eq!(generator.instance(), 400);
    /// ```
    ///
    /// Providing an invalid `instance` panics:
    ///
    /// ```should_panic
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let generator: Generator = Builder::new().instance(5000).build();
    /// ```
    #[inline]
    pub const fn instance(self, instance: u16) -> Self {
        match self.instance_checked(instance) {
            Some(this) => this,
            None => const_panic_new(),
        }
    }

    /// Sets the `instance` value of the `Builder`. Returns `None` if the provided `instance`
    /// exceeds the maximum value (2^10 -1).
    ///
    /// # Examples
    ///
    /// ```
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let builder = Builder::new().instance_checked(400);
    /// assert!(builder.is_some());
    /// ```
    ///
    /// Providing an invalid `instance` returns `None`:
    ///
    /// ```
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let builder = Builder::new().instance_checked(5000);
    /// assert!(builder.is_none());
    /// ```
    #[inline]
    pub const fn instance_checked(mut self, instance: u16) -> Option<Self> {
        if instance > INSTANCE_MAX {
            None
        } else {
            self.instance = instance;
            Some(self)
        }
    }

    /// Sets the `instance` value of the `Builder` without validating whether `instance` exceeds
    /// the maximum value (2^10 - 1).
    ///
    /// # Examples
    ///
    /// ```
    /// # use snowflaked::{Builder, Generator};
    /// #
    /// let generator: Generator = Builder::new().instance_unchecked(400).build();
    ///
    /// assert_eq!(generator.instance(), 400);
    /// ```
    #[inline]
    pub const fn instance_unchecked(mut self, instance: u16) -> Self {
        self.instance = instance;
        self
    }

    #[inline]
    pub const fn epoch(mut self, epoch: SystemTime) -> Self {
        self.epoch = epoch;
        self
    }

    /// Consumes this `Builder`, returning the constructed generator. This function works with both
    /// [`Generator`] and [`sync::Generator`].
    ///
    /// # Examples
    ///
    /// ```
    /// use snowflaked::{Builder, Generator};
    ///
    /// let mut generator = Builder::new().build::<Generator>();
    ///
    /// let id: u64 = generator.generate();
    /// ```
    ///
    /// A [`sync::Generator`] can be constructed in the same way:
    ///
    /// ```
    /// use snowflaked::Builder;
    /// use snowflaked::sync::Generator;
    ///
    /// let generator = Builder::new().build::<Generator>();
    ///
    /// let id: u64 = generator.generate();
    /// ```
    ///
    /// [`Generator`]: crate::Generator
    /// [`sync::Generator`]: crate::sync::Generator
    #[inline]
    pub fn build<T>(self) -> T
    where
        T: From<Self>,
    {
        T::from(self)
    }
}