mirror of
https://github.com/uuid-rs/uuid.git
synced 2025-09-29 22:10:50 +00:00
hacking the API to be backwards compatible
This commit is contained in:
parent
dbe1c7cb59
commit
a2b1258a04
30
src/lib.rs
30
src/lib.rs
@ -878,9 +878,7 @@ impl Uuid {
|
||||
/// value into more commonly-used formats, such as a unix timestamp.
|
||||
///
|
||||
/// [`Timestamp`]: v1/struct.Timestamp.html
|
||||
pub const fn get_timestamp(
|
||||
&self,
|
||||
) -> Option<(crate::timestamp::Timestamp, u16)> {
|
||||
pub const fn get_timestamp(&self) -> Option<crate::timestamp::Timestamp> {
|
||||
match self.get_version() {
|
||||
Some(Version::Mac) => {
|
||||
let bytes = self.as_bytes();
|
||||
@ -896,10 +894,7 @@ impl Uuid {
|
||||
let counter: u16 =
|
||||
((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
Some((
|
||||
crate::timestamp::Timestamp::from_rfc4122(ticks),
|
||||
counter,
|
||||
))
|
||||
Some(crate::timestamp::Timestamp::from_rfc4122(ticks, counter))
|
||||
}
|
||||
Some(Version::SortMac) => {
|
||||
let bytes = self.as_bytes();
|
||||
@ -915,10 +910,7 @@ impl Uuid {
|
||||
let counter: u16 =
|
||||
((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
Some((
|
||||
crate::timestamp::Timestamp::from_rfc4122(ticks),
|
||||
counter,
|
||||
))
|
||||
Some(crate::timestamp::Timestamp::from_rfc4122(ticks, counter))
|
||||
}
|
||||
Some(Version::SortRand) => {
|
||||
let bytes = self.as_bytes();
|
||||
@ -930,10 +922,18 @@ impl Uuid {
|
||||
| (bytes[5] as u64);
|
||||
let seconds = millis / 1000;
|
||||
let nanos = ((millis % 1000) * 1_000_000) as u32;
|
||||
Some((
|
||||
crate::timestamp::Timestamp::from_unix(seconds, nanos),
|
||||
0,
|
||||
))
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
{
|
||||
Some(Timestamp {
|
||||
seconds,
|
||||
nanos,
|
||||
counter: 0,
|
||||
})
|
||||
}
|
||||
#[cfg(not(any(feature = "v1", feature = "v6")))]
|
||||
{
|
||||
Some(Timestamp { seconds, nanos })
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ pub const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
|
||||
pub struct Timestamp {
|
||||
pub(crate) seconds: u64,
|
||||
pub(crate) nanos: u32,
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
pub(crate) counter: u16,
|
||||
}
|
||||
|
||||
impl Timestamp {
|
||||
@ -20,9 +22,21 @@ impl Timestamp {
|
||||
/// as the number of 100-nanosecond intervals elapsed since 00:00:00.00,
|
||||
/// 15 Oct 1582, "the date of the Gregorian reform of the Christian
|
||||
/// calendar."
|
||||
pub const fn from_rfc4122(ticks: u64) -> Self {
|
||||
pub const fn from_rfc4122(ticks: u64, _counter: u16) -> Self {
|
||||
let (seconds, nanos) = Self::rfc4122_to_unix(ticks);
|
||||
Timestamp { seconds, nanos }
|
||||
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
{
|
||||
Timestamp {
|
||||
seconds,
|
||||
nanos,
|
||||
counter: _counter,
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(feature = "v1", feature = "v6")))]
|
||||
{
|
||||
Timestamp { seconds, nanos }
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Timestamp` from a unix timestamp
|
||||
@ -33,13 +47,29 @@ impl Timestamp {
|
||||
/// `u32` fields representing the seconds, and "subsecond" or fractional
|
||||
/// nanoseconds elapsed since the timestamp's second began,
|
||||
/// respectively.
|
||||
pub const fn from_unix(seconds: u64, nanos: u32) -> Self {
|
||||
Timestamp { seconds, nanos }
|
||||
pub fn from_unix(
|
||||
_context: impl ClockSequence<Output = u16>,
|
||||
seconds: u64,
|
||||
nanos: u32,
|
||||
) -> Self {
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
{
|
||||
let counter = _context.generate_sequence(seconds, nanos);
|
||||
Timestamp {
|
||||
seconds,
|
||||
nanos,
|
||||
counter,
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(feature = "v1", feature = "v6")))]
|
||||
{
|
||||
Timestamp { seconds, nanos }
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Timestamp` from the current time of day
|
||||
/// according to Rust's SystemTime
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(all(feature = "std", not(any(feature = "v1", feature = "v6"))))]
|
||||
pub fn now() -> Self {
|
||||
let dur = std::time::SystemTime::UNIX_EPOCH
|
||||
.elapsed()
|
||||
@ -49,14 +79,30 @@ impl Timestamp {
|
||||
nanos: dur.subsec_nanos(),
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "std", any(feature = "v1", feature = "v6")))]
|
||||
pub fn now(context: impl ClockSequence<Output = u16>) -> Self {
|
||||
let dur = std::time::SystemTime::UNIX_EPOCH
|
||||
.elapsed()
|
||||
.expect("Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality");
|
||||
Timestamp {
|
||||
seconds: dur.as_secs(),
|
||||
nanos: dur.subsec_nanos(),
|
||||
counter: context
|
||||
.generate_sequence(dur.as_secs(), dur.subsec_nanos()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the raw RFC4122 timestamp "tick" values stored by the
|
||||
/// `Timestamp`.
|
||||
///
|
||||
/// The ticks represent the number of 100-nanosecond intervals
|
||||
/// since 00:00:00.00, 15 Oct 1582.
|
||||
pub const fn to_rfc4122(&self) -> u64 {
|
||||
Self::unix_to_rfc4122_ticks(self.seconds, self.nanos)
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
pub const fn to_rfc4122(&self) -> (u64, u16) {
|
||||
(
|
||||
Self::unix_to_rfc4122_ticks(self.seconds, self.nanos),
|
||||
self.counter,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the timestamp converted to the seconds and fractional
|
||||
@ -101,13 +147,21 @@ pub trait ClockSequence {
|
||||
/// Return an arbitrary width number that will be used as the "clock sequence" in
|
||||
/// the UUID. The number must be different if the time has changed since
|
||||
/// the last time a clock sequence was requested.
|
||||
fn next(&self, ts: &Timestamp) -> Self::Output;
|
||||
fn generate_sequence(
|
||||
&self,
|
||||
seconds: u64,
|
||||
subsec_nanos: u32,
|
||||
) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
|
||||
type Output = T::Output;
|
||||
fn next(&self, ts: &Timestamp) -> Self::Output {
|
||||
(**self).next(ts)
|
||||
fn generate_sequence(
|
||||
&self,
|
||||
seconds: u64,
|
||||
subsec_nanos: u32,
|
||||
) -> Self::Output {
|
||||
(**self).generate_sequence(seconds, subsec_nanos)
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +212,11 @@ pub mod context {
|
||||
|
||||
impl super::ClockSequence for Context {
|
||||
type Output = u16;
|
||||
fn next(&self, _: &super::Timestamp) -> Self::Output {
|
||||
fn generate_sequence(
|
||||
&self,
|
||||
_seconds: u64,
|
||||
_nanos: u32,
|
||||
) -> Self::Output {
|
||||
// RFC4122 reserves 2 bits of the clock sequence so the actual
|
||||
// maximum value is smaller than `u16::MAX`. Since we unconditionally
|
||||
// increment the clock sequence we want to wrap once it becomes larger
|
||||
|
41
src/v1.rs
41
src/v1.rs
@ -3,7 +3,7 @@
|
||||
//! Note that you need to enable the `v1` Cargo feature
|
||||
//! in order to use this module.
|
||||
|
||||
use crate::timestamp::{ClockSequence, Timestamp};
|
||||
use crate::timestamp::Timestamp;
|
||||
use crate::Uuid;
|
||||
|
||||
|
||||
@ -86,13 +86,8 @@ impl Uuid {
|
||||
/// [`Timestamp`]: v1/struct.Timestamp.html
|
||||
/// [`ClockSequence`]: v1/trait.ClockSequence.html
|
||||
/// [`Context`]: v1/struct.Context.html
|
||||
pub fn new_v1(
|
||||
ts: Timestamp,
|
||||
ctx: &impl ClockSequence<Output = u16>,
|
||||
node_id: &[u8; 6],
|
||||
) -> Self {
|
||||
let ticks = ts.to_rfc4122();
|
||||
let counter = ctx.next(&ts);
|
||||
pub fn new_v1(ts: Timestamp, node_id: &[u8; 6]) -> Self {
|
||||
let (ticks, counter) = ts.to_rfc4122();
|
||||
let time_low = (ticks & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
|
||||
let time_high_and_version =
|
||||
@ -116,9 +111,8 @@ impl Uuid {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Variant, Version};
|
||||
use std::string::ToString;
|
||||
|
||||
use crate::{std::string::ToString, Variant, Version};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
@ -131,8 +125,7 @@ mod tests {
|
||||
let context = Context::new(0);
|
||||
|
||||
let uuid = Uuid::new_v1(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
@ -143,9 +136,9 @@ mod tests {
|
||||
"20616934-4ba2-11e7-8000-010203040506"
|
||||
);
|
||||
|
||||
let ts = uuid.get_timestamp().unwrap().0.to_rfc4122();
|
||||
let ts = uuid.get_timestamp().unwrap().to_rfc4122();
|
||||
|
||||
assert_eq!(ts - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
|
||||
assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
|
||||
|
||||
// Ensure parsing the same UUID produces the same timestamp
|
||||
let parsed = Uuid::parse_str("20616934-4ba2-11e7-8000-010203040506").unwrap();
|
||||
@ -167,36 +160,32 @@ mod tests {
|
||||
let context = Context::new((u16::MAX >> 2) - 1);
|
||||
|
||||
let uuid1 = Uuid::new_v1(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
let time: u64 = 1_496_854_536;
|
||||
|
||||
let uuid2 = Uuid::new_v1(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
assert_eq!(uuid1.get_timestamp().unwrap().1, 16382);
|
||||
assert_eq!(uuid2.get_timestamp().unwrap().1, 0);
|
||||
assert_eq!(uuid1.get_timestamp().unwrap().to_rfc4122().1, 16382);
|
||||
assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 0);
|
||||
|
||||
let time = 1_496_854_535;
|
||||
|
||||
let uuid3 = Uuid::new_v1(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
let uuid4 = Uuid::new_v1(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
assert_eq!(uuid3.get_timestamp().unwrap().1, 1);
|
||||
assert_eq!(uuid4.get_timestamp().unwrap().1, 2);
|
||||
assert_eq!(uuid3.get_timestamp().unwrap().to_rfc4122().1, 1);
|
||||
assert_eq!(uuid4.get_timestamp().unwrap().to_rfc4122().1, 2);
|
||||
}
|
||||
}
|
||||
|
46
src/v6.rs
46
src/v6.rs
@ -41,9 +41,9 @@ impl Uuid {
|
||||
/// # use uuid::{Uuid, Timestamp, Context};
|
||||
/// # fn random_seed() -> u16 { 42 }
|
||||
/// let context = Context::new(random_seed());
|
||||
/// let ts = Timestamp::from_unix(1497624119, 1234);
|
||||
/// let ts = Timestamp::from_unix(context, 1497624119, 1234);
|
||||
///
|
||||
/// let uuid = Uuid::new_v6(ts, &context, &[1, 2, 3, 4, 5, 6]);
|
||||
/// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// uuid.hyphenated().to_string(),
|
||||
@ -55,10 +55,10 @@ impl Uuid {
|
||||
///
|
||||
/// ```
|
||||
/// # use uuid::{Uuid, Timestamp, Context};
|
||||
/// let context = Context::new(42);
|
||||
/// let ts = Timestamp::from_rfc4122(14976241191231231313);
|
||||
/// let context = Context::new(random_seed());
|
||||
/// let ts = Timestamp::from_rfc4122(14976241191231231313, context.generate_sequence() );
|
||||
///
|
||||
/// let uuid = Uuid::new_v6(ts, &context, &[1, 2, 3, 4, 5, 6]);
|
||||
/// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// uuid.hyphenated().to_string(),
|
||||
@ -76,13 +76,8 @@ impl Uuid {
|
||||
/// [`Timestamp`]: v1/struct.Timestamp.html
|
||||
/// [`ClockSequence`]: v1/trait.ClockSequence.html
|
||||
/// [`Context`]: v1/struct.Context.html
|
||||
pub fn new_v6(
|
||||
ts: Timestamp,
|
||||
context: impl ClockSequence<Output = u16>,
|
||||
node_id: &[u8; 6],
|
||||
) -> Self {
|
||||
let ticks = ts.to_rfc4122();
|
||||
let counter = context.next(&ts);
|
||||
pub fn new_v6(ts: Timestamp, node_id: &[u8; 6]) -> Self {
|
||||
let (ticks, counter) = ts.to_rfc4122();
|
||||
let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
|
||||
let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
|
||||
@ -120,8 +115,7 @@ mod tests {
|
||||
let context = Context::new(0);
|
||||
|
||||
let uuid = Uuid::new_v6(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
@ -132,9 +126,9 @@ mod tests {
|
||||
"1e74ba22-0616-6934-8000-010203040506"
|
||||
);
|
||||
|
||||
let ts = uuid.get_timestamp().unwrap().0.to_rfc4122();
|
||||
let ts = uuid.get_timestamp().unwrap().to_rfc4122();
|
||||
|
||||
assert_eq!(ts - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
|
||||
assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
|
||||
|
||||
// Ensure parsing the same UUID produces the same timestamp
|
||||
let parsed =
|
||||
@ -157,36 +151,32 @@ mod tests {
|
||||
let context = Context::new((u16::MAX >> 2) - 1);
|
||||
|
||||
let uuid1 = Uuid::new_v6(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
let time: u64 = 1_496_854_536;
|
||||
|
||||
let uuid2 = Uuid::new_v6(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
assert_eq!(uuid1.get_timestamp().unwrap().1, 16382);
|
||||
assert_eq!(uuid2.get_timestamp().unwrap().1, 0);
|
||||
assert_eq!(uuid1.get_timestamp().unwrap().to_rfc4122().1, 16382);
|
||||
assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 0);
|
||||
|
||||
let time = 1_496_854_535;
|
||||
|
||||
let uuid3 = Uuid::new_v6(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
let uuid4 = Uuid::new_v6(
|
||||
Timestamp::from_unix(time, time_fraction),
|
||||
&context,
|
||||
Timestamp::from_unix(&context, time, time_fraction),
|
||||
&node,
|
||||
);
|
||||
|
||||
assert_eq!(uuid3.get_timestamp().unwrap().1, 1);
|
||||
assert_eq!(uuid4.get_timestamp().unwrap().1, 2);
|
||||
assert_eq!(uuid3.get_timestamp().unwrap().counter, 1);
|
||||
assert_eq!(uuid4.get_timestamp().unwrap().counter, 2);
|
||||
}
|
||||
}
|
||||
|
19
src/v7.rs
19
src/v7.rs
@ -21,8 +21,8 @@ impl Uuid {
|
||||
///
|
||||
/// ```rust
|
||||
/// # use uuid::{Uuid, Timestamp};
|
||||
///
|
||||
/// let ts = Timestamp::from_unix(1497624119, 1234);
|
||||
/// # use uuid::v7::NullSequence;
|
||||
/// let ts = Timestamp::from_unix(NullSequence {}, 1497624119, 1234);
|
||||
///
|
||||
/// let uuid = Uuid::new_v7(ts);
|
||||
///
|
||||
@ -50,6 +50,15 @@ impl Uuid {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NullSequence {}
|
||||
|
||||
impl super::ClockSequence for NullSequence {
|
||||
type Output = u16;
|
||||
fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -64,7 +73,11 @@ mod tests {
|
||||
let time: u64 = 1_496_854_535;
|
||||
let time_fraction: u32 = 812_946_000;
|
||||
|
||||
let uuid = Uuid::new_v7(Timestamp::from_unix(time, time_fraction));
|
||||
let uuid = Uuid::new_v7(Timestamp::from_unix(
|
||||
NullSequence {},
|
||||
time,
|
||||
time_fraction,
|
||||
));
|
||||
let uustr = uuid.hyphenated().to_string();
|
||||
|
||||
assert_eq!(uuid.get_version(), Some(Version::SortRand));
|
||||
|
Loading…
x
Reference in New Issue
Block a user