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