summaryrefslogtreecommitdiffstats
path: root/vendor/uuid/src/v1.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/uuid/src/v1.rs')
-rw-r--r--vendor/uuid/src/v1.rs326
1 files changed, 326 insertions, 0 deletions
diff --git a/vendor/uuid/src/v1.rs b/vendor/uuid/src/v1.rs
new file mode 100644
index 000000000..de692b768
--- /dev/null
+++ b/vendor/uuid/src/v1.rs
@@ -0,0 +1,326 @@
+//! The implementation for Version 1 UUIDs.
+//!
+//! Note that you need feature `v1` in order to use these features.
+
+use crate::prelude::*;
+use core::sync::atomic;
+
+/// The number of 100 ns ticks between the UUID epoch
+/// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`.
+const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
+
+/// A thread-safe, stateful context for the v1 generator to help ensure
+/// process-wide uniqueness.
+#[derive(Debug)]
+pub struct Context {
+ count: atomic::AtomicUsize,
+}
+
+/// Stores the number of nanoseconds from an epoch and a counter for ensuring
+/// V1 ids generated on the same host are unique.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct Timestamp {
+ ticks: u64,
+ counter: u16,
+}
+
+impl Timestamp {
+ /// Construct a `Timestamp` from its raw component values: an RFC4122
+ /// timestamp and counter.
+ ///
+ /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format
+ /// 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."
+ ///
+ /// The counter value is used to differentiate between ids generated by
+ /// the same host computer in rapid succession (i.e. with the same observed
+ /// time). See the [`ClockSequence`] trait for a generic interface to any
+ /// counter generators that might be used.
+ ///
+ /// Internally, the timestamp is stored as a `u64`. For this reason, dates
+ /// prior to October 1582 are not supported.
+ ///
+ /// [`ClockSequence`]: trait.ClockSequence.html
+ pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self {
+ Timestamp { ticks, counter }
+ }
+
+ /// Construct a `Timestamp` from a unix timestamp and sequence-generating
+ /// `context`.
+ ///
+ /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's
+ /// `clock_gettime` and other popular implementations traditionally
+ /// represent this duration as a `timespec`: a struct with `u64` and
+ /// `u32` fields representing the seconds, and "subsecond" or fractional
+ /// nanoseconds elapsed since the timestamp's second began,
+ /// respectively.
+ ///
+ /// This constructs a `Timestamp` from the seconds and fractional
+ /// nanoseconds of a unix timestamp, converting the duration since 1970
+ /// into the number of 100-nanosecond intervals since 00:00:00.00, 15
+ /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`.
+ ///
+ /// The function is not guaranteed to produce monotonically increasing
+ /// values however. There is a slight possibility that two successive
+ /// equal time values could be supplied and the sequence counter wraps back
+ /// over to 0.
+ ///
+ /// If uniqueness and monotonicity is required, the user is responsible for
+ /// ensuring that the time value always increases between calls (including
+ /// between restarts of the process and device).
+ pub fn from_unix(
+ context: impl ClockSequence,
+ seconds: u64,
+ subsec_nanos: u32,
+ ) -> Self {
+ let counter = context.generate_sequence(seconds, subsec_nanos);
+ let ticks = UUID_TICKS_BETWEEN_EPOCHS
+ + seconds * 10_000_000
+ + u64::from(subsec_nanos) / 100;
+
+ Timestamp { ticks, counter }
+ }
+
+ /// Returns the raw RFC4122 timestamp and counter values stored by the
+ /// `Timestamp`.
+ ///
+ /// The timestamp (the first, `u64` element in the tuple) represents the
+ /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582.
+ /// The counter is used to differentiate between ids generated on the
+ /// same host computer with the same observed time.
+ pub const fn to_rfc4122(&self) -> (u64, u16) {
+ (self.ticks, self.counter)
+ }
+
+ /// Returns the timestamp converted to the seconds and fractional
+ /// nanoseconds since Jan 1 1970.
+ ///
+ /// Internally, the time is stored in 100-nanosecond intervals,
+ /// thus the maximum precision represented by the fractional nanoseconds
+ /// value is less than its unit size (100 ns vs. 1 ns).
+ pub const fn to_unix(&self) -> (u64, u32) {
+ (
+ (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000,
+ ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32
+ * 100,
+ )
+ }
+
+ /// Returns the timestamp converted into nanoseconds elapsed since Jan 1
+ /// 1970. Internally, the time is stored in 100-nanosecond intervals,
+ /// thus the maximum precision represented is less than the units it is
+ /// measured in (100 ns vs. 1 ns). The value returned represents the
+ /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond
+ /// units for convenience.
+ pub const fn to_unix_nanos(&self) -> u64 {
+ (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100
+ }
+}
+
+/// A trait that abstracts over generation of UUID v1 "Clock Sequence" values.
+pub trait ClockSequence {
+ /// Return a 16-bit 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 generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16;
+}
+
+impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T {
+ fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 {
+ (**self).generate_sequence(seconds, subsec_nanos)
+ }
+}
+
+impl Uuid {
+ /// Create a new UUID (version 1) using a time value + sequence +
+ /// *NodeId*.
+ ///
+ /// When generating [`Timestamp`]s using a [`ClockSequence`], this function
+ /// is only guaranteed to produce unique values if the following conditions
+ /// hold:
+ ///
+ /// 1. The *NodeId* is unique for this process,
+ /// 2. The *Context* is shared across all threads which are generating v1
+ /// UUIDs,
+ /// 3. The [`ClockSequence`] implementation reliably returns unique
+ /// clock sequences (this crate provides [`Context`] for this
+ /// purpose. However you can create your own [`ClockSequence`]
+ /// implementation, if [`Context`] does not meet your needs).
+ ///
+ /// The NodeID must be exactly 6 bytes long.
+ ///
+ /// Note that usage of this method requires the `v1` feature of this crate
+ /// to be enabled.
+ ///
+ /// # Examples
+ ///
+ /// A UUID can be created from a unix [`Timestamp`] with a
+ /// [`ClockSequence`]:
+ ///
+ /// ```rust
+ /// use uuid::v1::{Timestamp, Context};
+ /// use uuid::Uuid;
+ ///
+ /// let context = Context::new(42);
+ /// let ts = Timestamp::from_unix(&context, 1497624119, 1234);
+ /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID");
+ ///
+ /// assert_eq!(
+ /// uuid.to_hyphenated().to_string(),
+ /// "f3b4958c-52a1-11e7-802a-010203040506"
+ /// );
+ /// ```
+ ///
+ /// The timestamp can also be created manually as per RFC4122:
+ ///
+ /// ```
+ /// use uuid::v1::{Timestamp, Context};
+ /// use uuid::Uuid;
+ ///
+ /// let context = Context::new(42);
+ /// let ts = Timestamp::from_rfc4122(1497624119, 0);
+ /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID");
+ ///
+ /// assert_eq!(
+ /// uuid.to_hyphenated().to_string(),
+ /// "5943ee37-0000-1000-8000-010203040506"
+ /// );
+ /// ```
+ ///
+ /// [`Timestamp`]: v1/struct.Timestamp.html
+ /// [`ClockSequence`]: v1/struct.ClockSequence.html
+ /// [`Context`]: v1/struct.Context.html
+ pub fn new_v1(ts: Timestamp, node_id: &[u8]) -> Result<Self, crate::Error> {
+ const NODE_ID_LEN: usize = 6;
+
+ let len = node_id.len();
+ if len != NODE_ID_LEN {
+ Err(crate::builder::Error::new(NODE_ID_LEN, len))?;
+ }
+
+ let time_low = (ts.ticks & 0xFFFF_FFFF) as u32;
+ let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16;
+ let time_high_and_version =
+ (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
+
+ let mut d4 = [0; 8];
+
+ {
+ d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80;
+ d4[1] = (ts.counter & 0xFF) as u8;
+ }
+
+ d4[2..].copy_from_slice(node_id);
+
+ Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
+ }
+
+ /// Returns an optional [`Timestamp`] storing the timestamp and
+ /// counter portion parsed from a V1 UUID.
+ ///
+ /// Returns `None` if the supplied UUID is not V1.
+ ///
+ /// The V1 timestamp format defined in RFC4122 specifies a 60-bit
+ /// integer representing the number of 100-nanosecond intervals
+ /// since 00:00:00.00, 15 Oct 1582.
+ ///
+ /// [`Timestamp`] offers several options for converting the raw RFC4122
+ /// value into more commonly-used formats, such as a unix timestamp.
+ ///
+ /// [`Timestamp`]: v1/struct.Timestamp.html
+ pub fn to_timestamp(&self) -> Option<Timestamp> {
+ if self
+ .get_version()
+ .map(|v| v != Version::Mac)
+ .unwrap_or(true)
+ {
+ return None;
+ }
+
+ let ticks: u64 = u64::from(self.as_bytes()[6] & 0x0F) << 56
+ | u64::from(self.as_bytes()[7]) << 48
+ | u64::from(self.as_bytes()[4]) << 40
+ | u64::from(self.as_bytes()[5]) << 32
+ | u64::from(self.as_bytes()[0]) << 24
+ | u64::from(self.as_bytes()[1]) << 16
+ | u64::from(self.as_bytes()[2]) << 8
+ | u64::from(self.as_bytes()[3]);
+
+ let counter: u16 = u16::from(self.as_bytes()[8] & 0x3F) << 8
+ | u16::from(self.as_bytes()[9]);
+
+ Some(Timestamp::from_rfc4122(ticks, counter))
+ }
+}
+
+impl Context {
+ /// Creates a thread-safe, internally mutable context to help ensure
+ /// uniqueness.
+ ///
+ /// This is a context which can be shared across threads. It maintains an
+ /// internal counter that is incremented at every request, the value ends
+ /// up in the clock_seq portion of the UUID (the fourth group). This
+ /// will improve the probability that the UUID is unique across the
+ /// process.
+ pub const fn new(count: u16) -> Self {
+ Self {
+ count: atomic::AtomicUsize::new(count as usize),
+ }
+ }
+}
+
+impl ClockSequence for Context {
+ fn generate_sequence(&self, _: u64, _: u32) -> u16 {
+ (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::std::string::ToString;
+
+ #[test]
+ fn test_new_v1() {
+ let time: u64 = 1_496_854_535;
+ let time_fraction: u32 = 812_946_000;
+ let node = [1, 2, 3, 4, 5, 6];
+ let context = Context::new(0);
+
+ {
+ let uuid = Uuid::new_v1(
+ Timestamp::from_unix(&context, time, time_fraction),
+ &node,
+ )
+ .unwrap();
+
+ assert_eq!(uuid.get_version(), Some(Version::Mac));
+ assert_eq!(uuid.get_variant(), Some(Variant::RFC4122));
+ assert_eq!(
+ uuid.to_hyphenated().to_string(),
+ "20616934-4ba2-11e7-8000-010203040506"
+ );
+
+ let ts = uuid.to_timestamp().unwrap().to_rfc4122();
+
+ assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
+ assert_eq!(ts.1, 0);
+ };
+
+ {
+ let uuid2 = Uuid::new_v1(
+ Timestamp::from_unix(&context, time, time_fraction),
+ &node,
+ )
+ .unwrap();
+
+ assert_eq!(
+ uuid2.to_hyphenated().to_string(),
+ "20616934-4ba2-11e7-8001-010203040506"
+ );
+ assert_eq!(uuid2.to_timestamp().unwrap().to_rfc4122().1, 1)
+ };
+ }
+}