@@ -51,6 +51,170 @@ pub enum MaybeUnset<V> {
5151 Set ( V ) ,
5252}
5353
54+ /// Represents timeuuid (uuid V1) value
55+ ///
56+ /// This type has custom comparison logic which follows Scylla/Cassandra semantics.
57+ /// For details, see [`Ord` implementation](#impl-Ord-for-CqlTimeuuid).
58+ #[ derive( Debug , Clone , Copy , Eq ) ]
59+ pub struct CqlTimeuuid ( Uuid ) ;
60+
61+ /// [`Uuid`] delegate methods
62+ impl CqlTimeuuid {
63+ pub fn as_bytes ( & self ) -> & [ u8 ; 16 ] {
64+ self . 0 . as_bytes ( )
65+ }
66+
67+ pub fn as_u128 ( & self ) -> u128 {
68+ self . 0 . as_u128 ( )
69+ }
70+
71+ pub fn as_fields ( & self ) -> ( u32 , u16 , u16 , & [ u8 ; 8 ] ) {
72+ self . 0 . as_fields ( )
73+ }
74+
75+ pub fn as_u64_pair ( & self ) -> ( u64 , u64 ) {
76+ self . 0 . as_u64_pair ( )
77+ }
78+
79+ pub fn from_slice ( b : & [ u8 ] ) -> Result < Self , uuid:: Error > {
80+ Ok ( Self ( Uuid :: from_slice ( b) ?) )
81+ }
82+
83+ pub fn from_slice_le ( b : & [ u8 ] ) -> Result < Self , uuid:: Error > {
84+ Ok ( Self ( Uuid :: from_slice_le ( b) ?) )
85+ }
86+
87+ pub fn from_bytes ( bytes : [ u8 ; 16 ] ) -> Self {
88+ Self ( Uuid :: from_bytes ( bytes) )
89+ }
90+
91+ pub fn from_bytes_le ( bytes : [ u8 ; 16 ] ) -> Self {
92+ Self ( Uuid :: from_bytes_le ( bytes) )
93+ }
94+
95+ pub fn from_fields ( d1 : u32 , d2 : u16 , d3 : u16 , d4 : & [ u8 ; 8 ] ) -> Self {
96+ Self ( Uuid :: from_fields ( d1, d2, d3, d4) )
97+ }
98+
99+ pub fn from_fields_le ( d1 : u32 , d2 : u16 , d3 : u16 , d4 : & [ u8 ; 8 ] ) -> Self {
100+ Self ( Uuid :: from_fields_le ( d1, d2, d3, d4) )
101+ }
102+
103+ pub fn from_u128 ( v : u128 ) -> Self {
104+ Self ( Uuid :: from_u128 ( v) )
105+ }
106+
107+ pub fn from_u128_le ( v : u128 ) -> Self {
108+ Self ( Uuid :: from_u128_le ( v) )
109+ }
110+
111+ pub fn from_u64_pair ( high_bits : u64 , low_bits : u64 ) -> Self {
112+ Self ( Uuid :: from_u64_pair ( high_bits, low_bits) )
113+ }
114+ }
115+
116+ impl CqlTimeuuid {
117+ /// Read 8 most significant bytes of timeuuid from serialized bytes
118+ fn msb ( & self ) -> u64 {
119+ // Scylla and Cassandra use a standard UUID memory layout for MSB:
120+ // 4 bytes 2 bytes 2 bytes
121+ // time_low - time_mid - time_hi_and_version
122+ let bytes = self . 0 . as_bytes ( ) ;
123+ ( ( bytes[ 6 ] & 0x0F ) as u64 ) << 56
124+ | ( bytes[ 7 ] as u64 ) << 48
125+ | ( bytes[ 4 ] as u64 ) << 40
126+ | ( bytes[ 5 ] as u64 ) << 32
127+ | ( bytes[ 0 ] as u64 ) << 24
128+ | ( bytes[ 1 ] as u64 ) << 16
129+ | ( bytes[ 2 ] as u64 ) << 8
130+ | ( bytes[ 3 ] as u64 )
131+ }
132+
133+ fn lsb ( & self ) -> u64 {
134+ let bytes = self . 0 . as_bytes ( ) ;
135+ ( bytes[ 8 ] as u64 ) << 56
136+ | ( bytes[ 9 ] as u64 ) << 48
137+ | ( bytes[ 10 ] as u64 ) << 40
138+ | ( bytes[ 11 ] as u64 ) << 32
139+ | ( bytes[ 12 ] as u64 ) << 24
140+ | ( bytes[ 13 ] as u64 ) << 16
141+ | ( bytes[ 14 ] as u64 ) << 8
142+ | ( bytes[ 15 ] as u64 )
143+ }
144+
145+ fn lsb_signed ( & self ) -> u64 {
146+ self . lsb ( ) ^ 0x8080808080808080
147+ }
148+ }
149+
150+ impl std:: str:: FromStr for CqlTimeuuid {
151+ type Err = uuid:: Error ;
152+
153+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
154+ Ok ( Self ( Uuid :: from_str ( s) ?) )
155+ }
156+ }
157+
158+ impl std:: fmt:: Display for CqlTimeuuid {
159+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
160+ write ! ( f, "{}" , self . 0 )
161+ }
162+ }
163+
164+ impl AsRef < Uuid > for CqlTimeuuid {
165+ fn as_ref ( & self ) -> & Uuid {
166+ & self . 0
167+ }
168+ }
169+
170+ impl From < CqlTimeuuid > for Uuid {
171+ fn from ( value : CqlTimeuuid ) -> Self {
172+ value. 0
173+ }
174+ }
175+
176+ impl From < Uuid > for CqlTimeuuid {
177+ fn from ( value : Uuid ) -> Self {
178+ Self ( value)
179+ }
180+ }
181+
182+ /// Compare two values of timeuuid type.
183+ ///
184+ /// Cassandra legacy requires:
185+ /// - converting 8 most significant bytes to date, which is then compared.
186+ /// - masking off UUID version from the 8 ms-bytes during compare, to
187+ /// treat possible non-version-1 UUID the same way as UUID.
188+ /// - using signed compare for least significant bits.
189+ impl Ord for CqlTimeuuid {
190+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
191+ let mut res = self . msb ( ) . cmp ( & other. msb ( ) ) ;
192+ if let std:: cmp:: Ordering :: Equal = res {
193+ res = self . lsb_signed ( ) . cmp ( & other. lsb_signed ( ) ) ;
194+ }
195+ res
196+ }
197+ }
198+
199+ impl PartialOrd for CqlTimeuuid {
200+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
201+ Some ( self . cmp ( other) )
202+ }
203+ }
204+
205+ impl PartialEq for CqlTimeuuid {
206+ fn eq ( & self , other : & Self ) -> bool {
207+ self . cmp ( other) == std:: cmp:: Ordering :: Equal
208+ }
209+ }
210+
211+ impl std:: hash:: Hash for CqlTimeuuid {
212+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
213+ self . lsb_signed ( ) . hash ( state) ;
214+ self . msb ( ) . hash ( state) ;
215+ }
216+ }
217+
54218/// Native CQL date representation that allows for a bigger range of dates (-262145-1-1 to 262143-12-31).
55219///
56220/// Represented as number of days since -5877641-06-23 i.e. 2^31 days before unix epoch.
@@ -696,6 +860,12 @@ impl Value for Uuid {
696860 }
697861}
698862
863+ impl Value for CqlTimeuuid {
864+ fn serialize ( & self , buf : & mut Vec < u8 > ) -> Result < ( ) , ValueTooBig > {
865+ self . 0 . serialize ( buf)
866+ }
867+ }
868+
699869impl Value for BigInt {
700870 fn serialize ( & self , buf : & mut Vec < u8 > ) -> Result < ( ) , ValueTooBig > {
701871 let serialized = self . to_signed_bytes_be ( ) ;
0 commit comments