discord_cassandra_cpp/cassandra/
uuid.rs

1use crate::cassandra::error::*;
2use crate::cassandra::util::{Protected, ProtectedInner};
3
4use crate::cassandra_sys::cass_uuid_from_string_n;
5use crate::cassandra_sys::cass_uuid_gen_free;
6use crate::cassandra_sys::cass_uuid_gen_from_time;
7use crate::cassandra_sys::cass_uuid_gen_new;
8use crate::cassandra_sys::cass_uuid_gen_new_with_node;
9use crate::cassandra_sys::cass_uuid_gen_random;
10use crate::cassandra_sys::cass_uuid_gen_time;
11use crate::cassandra_sys::cass_uuid_max_from_time;
12use crate::cassandra_sys::cass_uuid_min_from_time;
13use crate::cassandra_sys::cass_uuid_string;
14use crate::cassandra_sys::cass_uuid_timestamp;
15use crate::cassandra_sys::cass_uuid_version;
16use crate::cassandra_sys::CassUuid as _Uuid;
17use crate::cassandra_sys::CassUuidGen as _UuidGen;
18
19use std::cmp::Ordering;
20use std::ffi::CStr;
21use std::fmt;
22use std::fmt::Formatter;
23use std::fmt::{Debug, Display};
24use std::mem;
25use std::os::raw::c_char;
26use std::str;
27
28const CASS_UUID_STRING_LENGTH: usize = 37;
29
30#[derive(Copy, Clone)]
31/// Version 1 (time-based) or version 4 (random) UUID.
32pub struct Uuid(_Uuid);
33
34impl ProtectedInner<_Uuid> for Uuid {
35    fn inner(&self) -> _Uuid {
36        self.0
37    }
38}
39
40impl Protected<_Uuid> for Uuid {
41    fn build(inner: _Uuid) -> Self {
42        Uuid(inner)
43    }
44}
45
46impl Default for Uuid {
47    fn default() -> Uuid {
48        unsafe { ::std::mem::zeroed() }
49    }
50}
51
52/// A UUID generator object.
53///
54/// Instances of the UUID generator object are thread-safe to generate UUIDs.
55#[derive(Debug)]
56pub struct UuidGen(*mut _UuidGen);
57unsafe impl Sync for UuidGen {}
58unsafe impl Send for UuidGen {}
59
60impl Drop for UuidGen {
61    fn drop(&mut self) {
62        unsafe { cass_uuid_gen_free(self.0) }
63    }
64}
65
66impl Debug for Uuid {
67    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
68        fmt::Display::fmt(self, f)
69    }
70}
71
72impl Display for Uuid {
73    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74        unsafe {
75            // Allocate an array large enough for cass_uuid_string to write to.
76            let mut buf = [0u8; CASS_UUID_STRING_LENGTH];
77            cass_uuid_string(self.0, buf.as_mut_ptr() as *mut c_char);
78            let str = CStr::from_bytes_with_nul(&buf)
79                .map_err(|_| fmt::Error)?
80                .to_str()
81                .map_err(|_| fmt::Error)?;
82            fmt::Display::fmt(&str, f)
83        }
84    }
85}
86
87impl Uuid {
88    /// Generates a V1 (time) UUID for the specified time.
89    pub fn min_from_time(&mut self, time: u64) {
90        unsafe { cass_uuid_min_from_time(time, &mut self.0) }
91    }
92
93    /// Sets the UUID to the minimum V1 (time) value for the specified tim
94    pub fn max_from_time(&mut self, time: u64) {
95        unsafe { cass_uuid_max_from_time(time, &mut self.0) }
96    }
97
98    /// Gets the timestamp for a V1 UUID
99    pub fn timestamp(&self) -> u64 {
100        unsafe { cass_uuid_timestamp(self.0) }
101    }
102
103    /// Gets the version for a UUID
104    pub fn version(&self) -> u8 {
105        unsafe { cass_uuid_version(self.0) }
106    }
107}
108
109impl From<uuid::Uuid> for Uuid {
110    fn from(id: uuid::Uuid) -> Uuid {
111        // implementation taken from Datastax C/C++ driver
112        // serialization.hpp, encode_uuid()
113        let input = id.as_bytes();
114
115        let mut time_and_version = 0u64;
116        time_and_version |= input[3] as u64;
117        time_and_version |= (input[2] as u64) << 8;
118        time_and_version |= (input[1] as u64) << 16;
119        time_and_version |= (input[0] as u64) << 24;
120
121        time_and_version |= (input[5] as u64) << 32;
122        time_and_version |= (input[4] as u64) << 40;
123
124        time_and_version |= (input[7] as u64) << 48;
125        time_and_version |= (input[6] as u64) << 56;
126
127        let mut clock_seq_and_node = 0u64;
128        for i in 0..8 {
129            clock_seq_and_node |= (input[15 - i] as u64) << (8 * i);
130        }
131        Uuid(_Uuid {
132            time_and_version,
133            clock_seq_and_node,
134        })
135    }
136}
137
138impl From<Uuid> for uuid::Uuid {
139    fn from(id: Uuid) -> uuid::Uuid {
140        // implementation taken from Datastax C/C++ driver
141        // serialization.hpp decode_uuid()
142        let mut output = [0u8; 16];
143        output[3] = id.0.time_and_version as u8;
144        output[2] = (id.0.time_and_version >> 8) as u8;
145        output[1] = (id.0.time_and_version >> 16) as u8;
146        output[0] = (id.0.time_and_version >> 24) as u8;
147
148        output[5] = (id.0.time_and_version >> 32) as u8;
149        output[4] = (id.0.time_and_version >> 40) as u8;
150
151        output[7] = (id.0.time_and_version >> 48) as u8;
152        output[6] = (id.0.time_and_version >> 56) as u8;
153
154        for i in 0..8 {
155            output[15 - i] = (id.0.clock_seq_and_node >> (8 * i)) as u8;
156        }
157        uuid::Uuid::from_bytes(output)
158    }
159}
160
161impl str::FromStr for Uuid {
162    type Err = Error;
163    fn from_str(str: &str) -> Result<Uuid> {
164        unsafe {
165            let mut uuid = mem::zeroed();
166            let str_ptr = str.as_ptr() as *const c_char;
167            cass_uuid_from_string_n(str_ptr, str.len(), &mut uuid)
168                .to_result(())
169                .and_then(|_| Ok(Uuid(uuid)))
170        }
171    }
172}
173
174impl PartialEq for Uuid {
175    fn eq(&self, other: &Uuid) -> bool {
176        self.0.time_and_version == other.0.time_and_version
177            && self.0.clock_seq_and_node == other.0.clock_seq_and_node
178    }
179}
180
181impl Eq for Uuid {}
182
183impl Ord for Uuid {
184    fn cmp(&self, other: &Uuid) -> Ordering {
185        self.0
186            .time_and_version
187            .cmp(&other.0.time_and_version)
188            .then(self.0.clock_seq_and_node.cmp(&other.0.clock_seq_and_node))
189    }
190}
191
192impl PartialOrd for Uuid {
193    fn partial_cmp(&self, other: &Uuid) -> Option<Ordering> {
194        Some(self.cmp(other))
195    }
196}
197
198impl Default for UuidGen {
199    /// Creates a new thread-safe UUID generator
200    fn default() -> Self {
201        unsafe { UuidGen(cass_uuid_gen_new()) }
202    }
203}
204
205impl UuidGen {
206    /// Creates a new UUID generator with custom node information.
207    /// <b>Note:</b> This object is thread-safe. It is best practice to create and reuse
208    /// a single object per application.
209    pub fn new_with_node(node: u64) -> UuidGen {
210        unsafe { UuidGen(cass_uuid_gen_new_with_node(node)) }
211    }
212
213    /// Generates a V1 (time) UUID.
214    pub fn gen_time(&self) -> Uuid {
215        unsafe {
216            let mut output: _Uuid = mem::zeroed();
217            cass_uuid_gen_time(self.0, &mut output);
218            Uuid(output)
219        }
220    }
221
222    /// Generates a new V4 (random) UUID
223    pub fn gen_random(&self) -> Uuid {
224        unsafe {
225            let mut output: _Uuid = mem::zeroed();
226            cass_uuid_gen_random(self.0, &mut output);
227            Uuid(output)
228        }
229    }
230
231    /// Generates a V1 (time) UUID for the specified time.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// # use cassandra_cpp::{UuidGen, Uuid};
237    /// # #[allow(dead_code)]
238    /// # fn example() -> Uuid {
239    /// let generator = UuidGen::default();
240    /// let uuid = generator.gen_from_time(1457486866742u64);
241    /// # uuid
242    /// # }
243    /// ```
244    pub fn gen_from_time(&self, timestamp: u64) -> Uuid {
245        unsafe {
246            let mut output: _Uuid = mem::zeroed();
247            cass_uuid_gen_from_time(self.0, timestamp, &mut output);
248            Uuid(output)
249        }
250    }
251}
252
253#[test]
254#[allow(unused_variables)]
255fn test_uuid_display_gentime() {
256    let generator = UuidGen::default();
257    let uuid = generator.gen_from_time(1457486866742u64);
258    assert_eq!(uuid.timestamp(), 1457486866742u64);
259    let uuidstr = format!("{}", uuid); // Test Display trait
260}
261
262#[test]
263#[allow(unused_variables)]
264fn test_uuid_debug_genrand() {
265    let generator = UuidGen::default();
266    let uuid = generator.gen_random();
267    let uuidstr = format!("{:?}", uuid); // Test Debug trait
268}