0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-01-05 18:37:56 +00:00
libsql/bottomless/src/uuid_utils.rs
2023-10-17 17:41:26 +02:00

70 lines
2.1 KiB
Rust

// Copy-pasted from uuid crate to avoid their uuid_unstable flag guard.
// Once uuid v7 is standardized and stabilized, we can go back to using uuid::new_v7() directly.
use uuid::{NoContext, Timestamp, Uuid};
fn bytes() -> [u8; 16] {
rand::random()
}
pub(crate) const fn encode_unix_timestamp_millis(millis: u64, random_bytes: &[u8; 10]) -> Uuid {
let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
let millis_low = (millis & 0xFFFF) as u16;
let random_and_version =
(random_bytes[1] as u16 | ((random_bytes[0] as u16) << 8) & 0x0FFF) | (0x7 << 12);
let mut d4 = [0; 8];
d4[0] = (random_bytes[2] & 0x3F) | 0x80;
d4[1] = random_bytes[3];
d4[2] = random_bytes[4];
d4[3] = random_bytes[5];
d4[4] = random_bytes[6];
d4[5] = random_bytes[7];
d4[6] = random_bytes[8];
d4[7] = random_bytes[9];
Uuid::from_fields(millis_high, millis_low, random_and_version, &d4)
}
pub fn new_v7(ts: Timestamp) -> Uuid {
let (secs, nanos) = ts.to_unix();
let millis = (secs * 1000).saturating_add(nanos as u64 / 1_000_000);
encode_unix_timestamp_millis(millis, &bytes()[..10].try_into().unwrap())
}
pub(crate) fn decode_unix_timestamp(uuid: &Uuid) -> Timestamp {
// taken from uuid crate (unsafe features)
let bytes = uuid.as_bytes();
let millis: u64 = (bytes[0] as u64) << 40
| (bytes[1] as u64) << 32
| (bytes[2] as u64) << 24
| (bytes[3] as u64) << 16
| (bytes[4] as u64) << 8
| (bytes[5] as u64);
let seconds = millis / 1000;
let nanos = ((millis % 1000) * 1_000_000) as u32;
Timestamp::from_unix(NoContext, seconds, nanos)
}
#[cfg(test)]
mod test {
use crate::uuid_utils::{decode_unix_timestamp, new_v7};
use uuid::{NoContext, Timestamp};
#[test]
fn timestamp_uuid_conversion() {
let ts = Timestamp::now(NoContext);
let uuid = new_v7(ts);
let actual = decode_unix_timestamp(&uuid);
//TODO: information loss on encoding?
let (s1, _) = actual.to_unix();
let (s2, _) = ts.to_unix();
assert_eq!(s1, s2);
}
}