1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//! The implementation for Version 1 [`Uuid`]s.
//!
//! Note that you need feature `v1` in order to use these features.
//!
//! [`Uuid`]: ../struct.Uuid.html

use core::sync::atomic;
use prelude::*;

/// A thread-safe, stateful context for the v1 generator to help ensure
/// process-wide uniqueness.
#[derive(Debug)]
pub struct Context {
    count: atomic::AtomicUsize,
}

/// 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, nano_seconds: u32) -> u16;
}

impl Uuid {
    /// Create a new [`Uuid`] (version 1) using a time value + sequence +
    /// *NodeId*.
    ///
    /// This expects two values representing a monotonically increasing value
    /// as well as a unique 6 byte NodeId, and an implementation of
    /// [`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
    ///    [`Uuid`]s,
    /// 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. If the NodeID is not a valid
    /// length this will return a [`ParseError`]`::InvalidLength`.
    ///
    /// 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).
    ///
    /// Note that usage of this method requires the `v1` feature of this crate
    /// to be enabled.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```rust
    /// use uuid::v1::Context;
    /// use uuid::Uuid;
    ///
    /// let context = Context::new(42);
    /// if let Ok(uuid) =
    ///     Uuid::new_v1(&context, 1497624119, 1234, &[1, 2, 3, 4, 5, 6])
    /// {
    ///     assert_eq!(
    ///         uuid.to_hyphenated().to_string(),
    ///         "f3b4958c-52a1-11e7-802a-010203040506"
    ///     )
    /// } else {
    ///     panic!()
    /// }
    /// ```
    ///
    /// [`ParseError`]: ../enum.ParseError.html
    /// [`Uuid`]: ../struct.Uuid.html
    /// [`ClockSequence`]: struct.ClockSequence.html
    /// [`Context`]: struct.Context.html
    pub fn new_v1<T>(
        context: &T,
        seconds: u64,
        nano_seconds: u32,
        node_id: &[u8],
    ) -> Result<Self, ::BytesError>
    where
        T: ClockSequence,
    {
        const NODE_ID_LEN: usize = 6;

        let len = node_id.len();
        if len != NODE_ID_LEN {
            return Err(::BytesError::new(NODE_ID_LEN, len));
        }

        let time_low;
        let time_mid;
        let time_high_and_version;

        {
            /// 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;

            let timestamp =
                seconds * 10_000_000 + u64::from(nano_seconds / 100);
            let uuid_time = timestamp + UUID_TICKS_BETWEEN_EPOCHS;

            time_low = (uuid_time & 0xFFFF_FFFF) as u32;
            time_mid = ((uuid_time >> 32) & 0xFFFF) as u16;
            time_high_and_version =
                (((uuid_time >> 48) & 0x0FFF) as u16) | (1 << 12);
        }

        let mut d4 = [0; 8];

        {
            let count = context.generate_sequence(seconds, nano_seconds);
            d4[0] = (((count & 0x3F00) >> 8) as u8) | 0x80;
            d4[1] = (count & 0xFF) as u8;
        }

        d4[2..].copy_from_slice(node_id);

        Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
    }
}

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.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    pub 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 {
    #[test]
    fn test_new_v1() {
        use super::Context;
        use prelude::*;

        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(&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();

            assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
            assert_eq!(ts.1, 0);
        };

        {
            let uuid2 =
                Uuid::new_v1(&context, time, time_fraction, &node).unwrap();

            assert_eq!(
                uuid2.to_hyphenated().to_string(),
                "20616934-4ba2-11e7-8001-010203040506"
            );
            assert_eq!(uuid2.to_timestamp().unwrap().1, 1)
        };
    }
}