oats/
lib.rs

1//! This crate provides a simple and efficient way to generate globally unique identifiers.
2
3/// The bowl is used for generating Oat values in unified way.
4pub mod bowl;
5
6/// The oats are globally unique identifiers.
7pub mod oat;
8
9/// The region moduele contains predefined regions
10pub mod region;
11
12#[cfg(test)]
13mod tests {
14    /// This module contains the implementation of the `bowl` module.
15    mod bowl {
16        use std::thread;
17
18        use crate::bowl::{Bowl, GenerationBehavior, WrappedBowl};
19        use crate::oat::Oat;
20
21        /// Test function for generating Oat values using a WrappedBowl with normal generation behavior.
22        #[test]
23        fn test_wrapped_bowl_generate() {
24            // Create a WrappedBowl instance with node id 1 and normal generation behavior
25            let wrapped_bowl: WrappedBowl = WrappedBowl::of(1, GenerationBehavior::Normal, None);
26            test_wrapped_bowl_generate_definition(wrapped_bowl)
27        }
28
29        /// Test function for generating Oat values using a WrappedBowl with lazy generation behavior.
30        #[test]
31        fn test_wrapped_bowl_generate_lazy() {
32            // Create a WrappedBowl instance with node id 1 and lazy generation behavior
33            let wrapped_bowl: WrappedBowl = WrappedBowl::of(1, GenerationBehavior::Lazy, None);
34            test_wrapped_bowl_generate_definition(wrapped_bowl)
35        }
36
37        /// Test function for creating a Bowl with Realtime generation behavior and generating Oat values.
38        #[test]
39        fn test_bowl_new_seq_realtime() {
40            let mut bowl: Bowl = Bowl::of(1, GenerationBehavior::Realtime, None);
41
42            // Generate 10 Oat values with the Realtime generation behavior mode
43            let oats: Vec<u16> = (0..10).map(|_| bowl.new_seq()).collect();
44
45            // Check that the sequence numbers of the Oat values are increasing
46            assert!(oats.windows(2).all(|window| window[0] < window[1]));
47        }
48
49        /// Test function for generating Oat values using a WrappedBowl in a multi-threaded environment.
50        #[test]
51        fn test_wrapped_bowl_in_multi_thread_env() {
52            let wrapped: WrappedBowl = WrappedBowl::of(1, GenerationBehavior::Normal, None);
53            let mut handles = vec![];
54
55            for _ in 0..10 {
56                let clone = wrapped.clone();
57                handles.push(thread::spawn(move || {
58                    clone.generate();
59                }));
60            }
61
62            handles.into_iter().for_each(|h| h.join().unwrap());
63        }
64
65        /// Test function for generating Oat values using a WrappedBowl.
66        fn test_wrapped_bowl_generate_definition(wrapped_bowl: WrappedBowl) {
67            // Generate 10 Oat values
68            let oats: Vec<Oat> = (0..4095).map(|_| wrapped_bowl.generate()).collect();
69
70            // Check that the Oat values have the correct node id
71            assert!(oats.iter().all(|oat| oat.node() == 1));
72
73            // Check that the Oat values have increasing sequence numbers
74            assert!(oats
75                .windows(2)
76                .all(|window| window[0].seq() < window[1].seq()));
77
78            // Check if seq restarts
79            let oat = wrapped_bowl.generate();
80            assert_eq!(oat.seq(), 0);
81            assert_eq!(oat.node(), 1);
82            assert!(oat.timestamp() > oats.last().unwrap().timestamp())
83        }
84    }
85
86    /// The `oat` module contains tests for the `Oat` struct.
87    mod oat {
88        use crate::oat::Oat;
89
90        /// Test the `to_string` method of the `Oat` struct.
91        #[test]
92        fn test_to_string() {
93            let oat = Oat::of(1, 3, 1671800400_000);
94            let s = oat.to_string();
95
96            assert_eq!(s, "X1AwCIGvFTGAA");
97        }
98
99        /// Test the `to_bytes` method of the `Oat` struct.
100        #[test]
101        fn test_to_bytes() {
102            let oat = Oat::of(1, 3, 1671800400_000);
103            let b: [u8; 9] = oat.to_bytes();
104
105            assert_eq!(b, [1, 0x03, 0x0, 0x88, 0x1A, 0xF1, 0x53, 0x18, 0x0]);
106        }
107
108        /// Test the `into` method of the `Oat` struct.
109        #[test]
110        fn test_into_bytes() {
111            let oat = Oat::of(1, 3, 1671800400_000);
112            let b: [u8; 9] = oat.into();
113
114            assert_eq!(b, [1, 0x03, 0x0, 0x88, 0x1A, 0xF1, 0x53, 0x18, 0x0]);
115        }
116
117        /// Test the `from_string` method of the `Oat` struct.
118        #[test]
119        fn test_from_string() {
120            let oat = Oat::from_string("X1AwCIGvFTGAA").unwrap();
121
122            assert_eq!(oat.node(), 1);
123            assert_eq!(oat.seq(), 3);
124            assert_eq!(oat.timestamp(), 1671800400_000);
125        }
126
127        /// Test the `from_string_unchecked` method of the `Oat` struct.
128        #[test]
129        fn test_from_string_unchecked() {
130            let oat = Oat::from_string_unchecked("X1AwCIGvFTGAA");
131
132            assert_eq!(oat.node(), 1);
133            assert_eq!(oat.seq(), 3);
134            assert_eq!(oat.timestamp(), 1671800400_000);
135        }
136
137        /// Test the `from_bytes` method of the `Oat` struct.
138        #[test]
139        fn test_from_bytes() {
140            let oat = Oat::from_bytes([1, 0x03, 0x0, 0x88, 0x1A, 0xF1, 0x53, 0x18, 0x0]);
141
142            assert_eq!(oat.node(), 1);
143            assert_eq!(oat.seq(), 3);
144            assert_eq!(oat.timestamp(), 1671800400_000);
145        }
146
147        /// Test the `from_bytes_ref` method of the `Oat` struct.
148        #[test]
149        fn test_from_bytes_ref() {
150            let oat =
151                Oat::from_bytes_ref(&[1, 0x03, 0x0, 0x88, 0x1A, 0xF1, 0x53, 0x18, 0x0]).unwrap();
152
153            assert_eq!(oat.node(), 1);
154            assert_eq!(oat.seq(), 3);
155            assert_eq!(oat.timestamp(), 1671800400_000);
156        }
157
158        /// Test the `from_bytes` method of the `Oat` struct with an invalid length.
159        #[test]
160        fn test_from_bytes_ref_invalid_length() {
161            let oat = Oat::from_bytes_ref(&[1, 0x03, 0x0, 0x88, 0x1A, 0xF1, 0x53, 0x18]);
162
163            assert!(oat.is_err());
164            assert_eq!(
165                oat.err().unwrap(),
166                crate::oat::ParseOatError::InvalidLUIDLength(8)
167            );
168        }
169
170        #[test]
171        #[should_panic]
172        fn test_of_invalid_seq_length() {
173            let oat = Oat::of(1, 1 << 12, 0);
174            assert_eq!(oat.node(), 1);
175            assert_eq!(oat.seq(), 0x1000);
176            assert_eq!(oat.timestamp(), 0);
177        }
178
179        #[test]
180        #[should_panic]
181        fn test_of_invalid_timestamp_length() {
182            let oat = Oat::of(1, 0xFF, 1 << 44);
183            assert_eq!(oat.node(), 1);
184            assert_eq!(oat.seq(), 0x1000);
185            assert_eq!(oat.timestamp(), 0);
186        }
187        
188    }
189}