Skip to content

Commit db7e05a

Browse files
committed
Make UUIDv1 (and others) public
1 parent 79b81c9 commit db7e05a

16 files changed

+434
-198
lines changed

Sources/UUIDKit/ClockSequence.swift

Lines changed: 0 additions & 5 deletions
This file was deleted.

Sources/UUIDKit/Namespace.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,31 @@ extension UUID {
55
///
66
/// You can generate a new UUID as a namespace or use one of the pre-defined values
77
/// (`.dns`, `.url`, `.oid` or `.x500`).
8-
public struct Namespace: Hashable, RawRepresentable {
8+
public struct Namespace: Codable, Hashable, LosslessStringConvertible, RawRepresentable {
99
/// Creates a namespace with the specified UUID.
1010
///
1111
/// - parameter uuid: The UUID to use as the namespace.
1212
public init(_ uuid: UUID) {
13-
self.init(rawValue: uuid)
13+
self.rawValue = uuid
1414
}
1515

1616
public init(rawValue: UUID) {
1717
self.rawValue = rawValue
1818
}
1919

20+
public init?(_ description: String) {
21+
guard let rawValue = UUID(uuidString: description) else {
22+
return nil
23+
}
24+
self.rawValue = rawValue
25+
}
26+
2027
public let rawValue: UUID
2128

29+
public var description: String {
30+
rawValue.description
31+
}
32+
2233
/// The namespace to use with a fully-qualified domain name.
2334
public static let dns = Namespace(UUID(
2435
uuid: (0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8)

Sources/UUIDKit/NodeID.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

Sources/UUIDKit/Timestamp.swift

Lines changed: 0 additions & 65 deletions
This file was deleted.

Sources/UUIDKit/UUIDv1.swift

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,89 @@ extension UUID {
1717
}
1818
}
1919

20-
extension UUID {
21-
internal struct UUIDv1 {
22-
public init() {
23-
self.init(nodeID: .default)
24-
}
25-
26-
public init(nodeID: NodeID) {
27-
let (timestamp, clockSequence) = Clock.default.next()
28-
self.init(timestamp: timestamp, clockSequence: clockSequence, nodeID: nodeID)
20+
public struct UUIDv1: Codable, Hashable, LosslessStringConvertible, RawRepresentable {
21+
public init() {
22+
self.init(node: .current)
23+
}
24+
25+
public init(node: Node) {
26+
let (timestamp, clockSequence) = Clock.default.next()
27+
self.init(timestamp: timestamp, clockSequence: clockSequence, node: node)
28+
}
29+
30+
public init(timestamp: Timestamp, clockSequence: ClockSequence, node: Node) {
31+
var bytes = UUID.null.uuid
32+
bytes.0 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 24)
33+
bytes.1 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 16)
34+
bytes.2 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 8)
35+
bytes.3 = UInt8(truncatingIfNeeded: timestamp.rawValue)
36+
bytes.4 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 40)
37+
bytes.5 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 32)
38+
bytes.6 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 56) & 0x0f | 0x10
39+
bytes.7 = UInt8(truncatingIfNeeded: timestamp.rawValue >> 48)
40+
bytes.8 = UInt8(truncatingIfNeeded: clockSequence.rawValue >> 8) & 0x3f | 0x80
41+
bytes.9 = UInt8(truncatingIfNeeded: clockSequence.rawValue)
42+
bytes.10 = UInt8(truncatingIfNeeded: node.rawValue >> 40)
43+
bytes.11 = UInt8(truncatingIfNeeded: node.rawValue >> 32)
44+
bytes.12 = UInt8(truncatingIfNeeded: node.rawValue >> 24)
45+
bytes.13 = UInt8(truncatingIfNeeded: node.rawValue >> 16)
46+
bytes.14 = UInt8(truncatingIfNeeded: node.rawValue >> 8)
47+
bytes.15 = UInt8(truncatingIfNeeded: node.rawValue)
48+
rawValue = UUID(uuid: bytes)
49+
assert(rawValue.version == 1)
50+
}
51+
52+
public init?(rawValue: UUID) {
53+
guard rawValue.version == 1 else {
54+
return nil
2955
}
30-
31-
public init(timestamp: Timestamp, clockSequence: ClockSequence, nodeID: NodeID) {
32-
let time = timestamp.rawValue
33-
var bytes = UUID.null.uuid
34-
bytes.0 = UInt8(truncatingIfNeeded: time >> 24)
35-
bytes.1 = UInt8(truncatingIfNeeded: time >> 16)
36-
bytes.2 = UInt8(truncatingIfNeeded: time >> 8)
37-
bytes.3 = UInt8(truncatingIfNeeded: time)
38-
bytes.4 = UInt8(truncatingIfNeeded: time >> 40)
39-
bytes.5 = UInt8(truncatingIfNeeded: time >> 32)
40-
bytes.6 = UInt8(truncatingIfNeeded: time >> 56) & 0x0f | 0x10
41-
bytes.7 = UInt8(truncatingIfNeeded: time >> 48)
42-
bytes.8 = UInt8(truncatingIfNeeded: clockSequence >> 8) & 0x3f | 0x80
43-
bytes.9 = UInt8(truncatingIfNeeded: clockSequence)
44-
(bytes.10, bytes.11, bytes.12, bytes.13, bytes.14, bytes.15) = nodeID.bytes
45-
rawValue = UUID(uuid: bytes)
46-
assert(rawValue.version == 1)
56+
self.rawValue = rawValue
57+
}
58+
59+
public init?(_ description: String) {
60+
guard let rawValue = UUID(uuidString: description), rawValue.version == 1 else {
61+
return nil
4762
}
48-
49-
public let rawValue: UUID
63+
self.rawValue = rawValue
64+
}
65+
66+
public let rawValue: UUID
67+
68+
public var timestamp: Timestamp {
69+
let bytes = rawValue.uuid
70+
var rawValue: UInt64 = 0
71+
rawValue |= UInt64(bytes.0) << 24
72+
rawValue |= UInt64(bytes.1) << 16
73+
rawValue |= UInt64(bytes.2) << 8
74+
rawValue |= UInt64(bytes.3)
75+
rawValue |= UInt64(bytes.4) << 40
76+
rawValue |= UInt64(bytes.5) << 32
77+
rawValue |= UInt64(bytes.6 & 0x0f) << 56
78+
rawValue |= UInt64(bytes.7) << 48
79+
return Timestamp(truncatingIfNeeded: rawValue)
80+
}
81+
82+
public var clockSequence: ClockSequence {
83+
let bytes = rawValue.uuid
84+
var rawValue: UInt16 = 0
85+
rawValue |= UInt16(bytes.8) << 8
86+
rawValue |= UInt16(bytes.9)
87+
return ClockSequence(truncatingIfNeeded: rawValue)
88+
}
89+
90+
public var node: Node {
91+
let bytes = rawValue.uuid
92+
var rawValue: UInt64 = 0
93+
rawValue |= UInt64(bytes.10) << 40
94+
rawValue |= UInt64(bytes.11) << 32
95+
rawValue |= UInt64(bytes.12) << 24
96+
rawValue |= UInt64(bytes.13) << 16
97+
rawValue |= UInt64(bytes.14) << 8
98+
rawValue |= UInt64(bytes.15)
99+
return Node(truncatingIfNeeded: rawValue)
100+
}
101+
102+
public var description: String {
103+
rawValue.description
50104
}
51105
}
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import Foundation
22

3-
extension UUID {
3+
extension UUIDv1 {
44
internal final class Clock {
55
func next() -> (timestamp: Timestamp, clockSequence: ClockSequence) {
66
queue.sync {
77
let timestamp = Timestamp()
88
if timestamp <= lastTimestamp {
9-
clockSequence = (clockSequence &+ 1) & 0x3f
9+
clockSequence = clockSequence.next
1010
}
1111
lastTimestamp = timestamp
1212
return (timestamp, clockSequence)
1313
}
1414
}
1515

16-
static let `default` = Clock()
16+
static let `default`: Clock = .init()
1717

18-
private let queue = DispatchQueue(label: "UUIDKit:Foundation.UUID.Clock")
19-
private var clockSequence = ClockSequence.random(in: 0...(.max)) & 0x3f
20-
private var lastTimestamp = Timestamp.zero
18+
private let queue: DispatchQueue = .init(label: "UUIDKit.UUIDv1.Clock")
19+
private var clockSequence: ClockSequence = .random()
20+
private var lastTimestamp: Timestamp = .zero
2121
}
2222
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Foundation
2+
3+
extension UUIDv1 {
4+
public struct ClockSequence: Hashable, RawRepresentable {
5+
public init<T>(truncatingIfNeeded source: T) where T: BinaryInteger {
6+
self.rawValue = UInt16(truncatingIfNeeded: source) & ~(.max << 14)
7+
}
8+
9+
public init?(rawValue: UInt16) {
10+
guard rawValue & (.max << 14) == 0 else {
11+
return nil
12+
}
13+
self.rawValue = rawValue
14+
}
15+
16+
public let rawValue: UInt16
17+
18+
public var next: ClockSequence {
19+
ClockSequence(truncatingIfNeeded: rawValue &+ 1)
20+
}
21+
22+
public static func random() -> ClockSequence {
23+
var generator = SystemRandomNumberGenerator()
24+
return random(using: &generator)
25+
}
26+
27+
public static func random<T>(using generator: inout T) -> ClockSequence where T: RandomNumberGenerator {
28+
ClockSequence(truncatingIfNeeded: generator.next())
29+
}
30+
}
31+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Foundation
2+
3+
extension UUIDv1 {
4+
public struct Node: Hashable, RawRepresentable {
5+
public init<T>(truncatingIfNeeded source: T) where T: BinaryInteger {
6+
self.rawValue = UInt64(truncatingIfNeeded: source) & ~(.max << 48)
7+
}
8+
9+
public init?(rawValue: UInt64) {
10+
guard rawValue & (.max << 48) == 0 else {
11+
return nil
12+
}
13+
self.rawValue = rawValue
14+
}
15+
16+
public let rawValue: UInt64
17+
18+
public static let current: Node = .random()
19+
20+
public static func random() -> Node {
21+
var generator = SystemRandomNumberGenerator()
22+
return random(using: &generator)
23+
}
24+
25+
public static func random<T>(using generator: inout T) -> Node where T: RandomNumberGenerator {
26+
Node(truncatingIfNeeded: generator.next() | 0x010000000000)
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)