|
6 | 6 | // Copyright © 2015 PureSwift. All rights reserved. |
7 | 7 | // |
8 | 8 |
|
9 | | -#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) |
10 | | - import Darwin |
11 | | - import Foundation |
12 | | -#elseif os(Linux) |
13 | | - import Glibc |
14 | | - import CUUID |
15 | | -#endif |
16 | | - |
17 | | -// MARK: - Linux |
18 | | - |
19 | | -#if os(Linux) || XcodeLinux |
| 9 | +/// A representation of a universally unique identifier (```UUID```). |
| 10 | +public struct UUID { |
20 | 11 |
|
21 | | - /// A representation of a universally unique identifier (```UUID```). |
22 | | - public struct UUID: ByteValue, Equatable, Hashable, RawRepresentable, CustomStringConvertible { |
23 | | - |
24 | | - // MARK: - Static Properties |
25 | | - |
26 | | - public static let length = 16 |
27 | | - public static let stringLength = 36 |
28 | | - public static let unformattedStringLength = 32 |
29 | | - |
30 | | - // MARK: - Properties |
31 | | - |
32 | | - public var bytes: uuid_t |
33 | | - |
34 | | - // MARK: - Initialization |
35 | | - |
36 | | - /// Create a new UUID with RFC 4122 version 4 random bytes |
37 | | - public init() { |
38 | | - |
39 | | - var uuid = uuid_t(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) |
40 | | - |
41 | | - withUnsafeMutablePointer(to: &uuid, { (valuePointer: UnsafeMutablePointer<uuid_t>) in |
42 | | - |
43 | | - uuid_generate(unsafeBitCast(valuePointer, to: UnsafeMutablePointer<UInt8>.self)) |
44 | | - }) |
45 | | - |
46 | | - self.bytes = uuid |
47 | | - } |
48 | | - |
49 | | - /// Initializes a UUID with the specified bytes. |
50 | | - public init(bytes: uuid_t) { |
51 | | - |
52 | | - self.bytes = bytes |
53 | | - } |
54 | | - } |
| 12 | + // MARK: - Properties |
55 | 13 |
|
56 | | - // MARK: - RawRepresentable |
| 14 | + public let uuid: uuid_t |
57 | 15 |
|
58 | | - public extension UUID { |
59 | | - |
60 | | - init?(rawValue: String) { |
61 | | - |
62 | | - let uuidPointer = UnsafeMutablePointer<uuid_t>.allocate(capacity: 1) |
63 | | - |
64 | | - defer { uuidPointer.deallocate(capacity: 1) } |
65 | | - |
66 | | - guard uuid_parse(rawValue, unsafeBitCast(uuidPointer, to: UnsafeMutablePointer<UInt8>.self)) != -1 |
67 | | - else { return nil } |
68 | | - |
69 | | - self.bytes = uuidPointer.pointee |
70 | | - } |
| 16 | + // MARK: - Initialization |
| 17 | + |
| 18 | + /// Create a new UUID with RFC 4122 version 4 random bytes |
| 19 | + public init() { |
71 | 20 |
|
72 | | - var rawValue: String { |
73 | | - |
74 | | - var uuidCopy = bytes |
75 | | - |
76 | | - var uuidString = POSIXUUIDStringType(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
77 | | - |
78 | | - // withUnsafeMutablePointer(&uuidCopy, &uuidString) { (uuidPointer: UnsafeMutablePointer<uuid_t>, uuidStringPointer: UnsafeMutablePointer<POSIXUUIDStringType>) -> Void in |
79 | | - |
80 | | - withUnsafeMutablePointer(to: &uuidCopy) { (uuidPointer: UnsafeMutablePointer<uuid_t>) in |
81 | | - |
82 | | - withUnsafeMutablePointer(to: &uuidString) { (uuidStringPointer: UnsafeMutablePointer<POSIXUUIDStringType>) in |
83 | | - |
84 | | - let stringBuffer = unsafeBitCast(uuidStringPointer, to: UnsafeMutablePointer<Int8>.self) |
85 | | - |
86 | | - let uuidBuffer = unsafeBitCast(uuidPointer, to: UnsafeMutablePointer<UInt8>.self) |
87 | | - |
88 | | - uuid_unparse(unsafeBitCast(uuidBuffer, to: UnsafePointer<UInt8>.self), stringBuffer) |
89 | | - } |
90 | | - } |
91 | | - |
92 | | - return withUnsafeMutablePointer(to: &uuidString, { (valuePointer: UnsafeMutablePointer<POSIXUUIDStringType>) -> String in |
93 | | - |
94 | | - let buffer = unsafeBitCast(valuePointer, to: UnsafeMutablePointer<CChar>.self) |
95 | | - |
96 | | - return String(validatingUTF8: unsafeBitCast(buffer, to: UnsafePointer<CChar>.self))! |
97 | | - }) |
98 | | - } |
| 21 | + let uuid = uuid_t(.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random,.random) |
| 22 | + self.init(uuid: uuid) |
99 | 23 | } |
100 | 24 |
|
101 | | - // MARK: - Hashable |
102 | | - |
103 | | - public extension UUID { |
104 | | - |
105 | | - var hashValue: Int { |
106 | | - |
107 | | - return toData().hashValue |
108 | | - } |
| 25 | + /// Create a UUID from a `uuid_t`. |
| 26 | + public init(uuid: uuid_t) { |
| 27 | + self.uuid = uuid |
109 | 28 | } |
110 | 29 |
|
111 | | - // MARK: - Equatable |
| 30 | + // MARK: - UUID String |
112 | 31 |
|
113 | | - public func == (lhs: UUID, rhs: UUID) -> Bool { |
114 | | - |
115 | | - return lhs.bytes.0 == rhs.bytes.0 && |
116 | | - lhs.bytes.1 == rhs.bytes.1 && |
117 | | - lhs.bytes.2 == rhs.bytes.2 && |
118 | | - lhs.bytes.3 == rhs.bytes.3 && |
119 | | - lhs.bytes.4 == rhs.bytes.4 && |
120 | | - lhs.bytes.5 == rhs.bytes.5 && |
121 | | - lhs.bytes.6 == rhs.bytes.6 && |
122 | | - lhs.bytes.7 == rhs.bytes.7 && |
123 | | - lhs.bytes.8 == rhs.bytes.8 && |
124 | | - lhs.bytes.9 == rhs.bytes.9 && |
125 | | - lhs.bytes.10 == rhs.bytes.10 && |
126 | | - lhs.bytes.11 == rhs.bytes.11 && |
127 | | - lhs.bytes.12 == rhs.bytes.12 && |
128 | | - lhs.bytes.13 == rhs.bytes.13 && |
129 | | - lhs.bytes.14 == rhs.bytes.14 && |
130 | | - lhs.bytes.15 == rhs.bytes.15 |
| 32 | + /// Create a UUID from a string such as "E621E1F8-C36C-495A-93FC-0C247A3E6E5F". |
| 33 | + /// |
| 34 | + /// Returns nil for invalid strings. |
| 35 | + public init?(uuidString string: String) { |
| 36 | + guard string.count == UUID.stringLength |
| 37 | + else { return nil } |
| 38 | + let components = string |
| 39 | + .split(separator: "-") |
| 40 | + guard components[0].count == 8, |
| 41 | + components[1].count == 4, |
| 42 | + components[2].count == 4, |
| 43 | + components[3].count == 4, |
| 44 | + components[4].count == 12 |
| 45 | + else { return nil } |
| 46 | + let hexString = components |
| 47 | + .reduce("") { $0 + $1 } |
| 48 | + assert(hexString.count == UUID.length * 2) |
| 49 | + guard let bytes = [UInt8](hexadecimal: hexString) |
| 50 | + else { return nil } |
| 51 | + assert(bytes.count == UUID.length) |
| 52 | + self.init(uuid: uuid_t(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15])) |
| 53 | + } |
| 54 | + |
| 55 | + /// Returns a string created from the UUID, such as "E621E1F8-C36C-495A-93FC-0C247A3E6E5F" |
| 56 | + public var uuidString: String { |
| 57 | + return uuid.0.toHexadecimal() |
| 58 | + + uuid.1.toHexadecimal() |
| 59 | + + uuid.2.toHexadecimal() |
| 60 | + + uuid.3.toHexadecimal() |
| 61 | + + "-" |
| 62 | + + uuid.4.toHexadecimal() |
| 63 | + + uuid.5.toHexadecimal() |
| 64 | + + "-" |
| 65 | + + uuid.6.toHexadecimal() |
| 66 | + + uuid.7.toHexadecimal() |
| 67 | + + "-" |
| 68 | + + uuid.8.toHexadecimal() |
| 69 | + + uuid.9.toHexadecimal() |
| 70 | + + "-" |
| 71 | + + uuid.10.toHexadecimal() |
| 72 | + + uuid.11.toHexadecimal() |
| 73 | + + uuid.12.toHexadecimal() |
| 74 | + + uuid.13.toHexadecimal() |
| 75 | + + uuid.14.toHexadecimal() |
| 76 | + + uuid.15.toHexadecimal() |
131 | 77 | } |
| 78 | +} |
132 | 79 |
|
133 | | -#endif |
| 80 | +internal extension SwiftFoundation.UUID { |
| 81 | + |
| 82 | + static var length: Int { return 16 } |
| 83 | + static var stringLength: Int { return 36 } |
| 84 | +} |
134 | 85 |
|
135 | | -// MARK: - Darwin |
| 86 | +// MARK: - Equatable |
136 | 87 |
|
137 | | -#if (os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) && !XcodeLinux |
| 88 | +extension SwiftFoundation.UUID: Equatable { |
138 | 89 |
|
139 | | - public typealias UUID = Foundation.UUID |
140 | | - |
141 | | - extension Foundation.UUID { |
142 | | - |
143 | | - public static var length: Int { return 16 } |
144 | | - public static var stringLength: Int { return 36 } |
145 | | - public static var unformattedStringLength: Int { return 32 } |
| 90 | + public static func == (lhs: SwiftFoundation.UUID, rhs: SwiftFoundation.UUID) -> Bool { |
| 91 | + return lhs.uuid.0 == rhs.uuid.0 && |
| 92 | + lhs.uuid.1 == rhs.uuid.1 && |
| 93 | + lhs.uuid.2 == rhs.uuid.2 && |
| 94 | + lhs.uuid.3 == rhs.uuid.3 && |
| 95 | + lhs.uuid.4 == rhs.uuid.4 && |
| 96 | + lhs.uuid.5 == rhs.uuid.5 && |
| 97 | + lhs.uuid.6 == rhs.uuid.6 && |
| 98 | + lhs.uuid.7 == rhs.uuid.7 && |
| 99 | + lhs.uuid.8 == rhs.uuid.8 && |
| 100 | + lhs.uuid.9 == rhs.uuid.9 && |
| 101 | + lhs.uuid.10 == rhs.uuid.10 && |
| 102 | + lhs.uuid.11 == rhs.uuid.11 && |
| 103 | + lhs.uuid.12 == rhs.uuid.12 && |
| 104 | + lhs.uuid.13 == rhs.uuid.13 && |
| 105 | + lhs.uuid.14 == rhs.uuid.14 && |
| 106 | + lhs.uuid.15 == rhs.uuid.15 |
146 | 107 | } |
| 108 | +} |
| 109 | + |
| 110 | +// MARK: - Hashable |
| 111 | + |
| 112 | +extension UUID: Hashable { |
147 | 113 |
|
148 | | - extension Foundation.UUID: ByteValue { |
149 | | - |
150 | | - @inline(__always) |
151 | | - public init(bytes: uuid_t) { |
152 | | - |
153 | | - self.init(uuid: bytes) |
154 | | - } |
155 | | - |
156 | | - public var bytes: uuid_t { |
157 | | - |
158 | | - @inline(__always) |
159 | | - get { return uuid } |
160 | | - |
161 | | - @inline(__always) |
162 | | - set { self = Foundation.UUID(uuid: newValue) } |
163 | | - } |
| 114 | + public func hash(into hasher: inout Hasher) { |
| 115 | + withUnsafeBytes(of: uuid) { hasher.combine(bytes: $0) } |
164 | 116 | } |
| 117 | +} |
| 118 | + |
| 119 | +// MARK: - CustomStringConvertible |
| 120 | + |
| 121 | +extension UUID: CustomStringConvertible { |
165 | 122 |
|
166 | | - extension Foundation.UUID: RawRepresentable { |
167 | | - |
168 | | - @inline(__always) |
169 | | - public init?(rawValue uuidString: String) { |
170 | | - |
171 | | - self.init(uuidString: uuidString) |
172 | | - } |
173 | | - |
174 | | - public var rawValue: String { |
175 | | - |
176 | | - return uuidString |
177 | | - } |
| 123 | + public var description: String { |
| 124 | + return uuidString |
178 | 125 | } |
179 | | - |
180 | | -#endif |
| 126 | +} |
181 | 127 |
|
182 | | -// MARK: - DataConvertible |
| 128 | +// MARK: - CustomReflectable |
183 | 129 |
|
184 | | -extension UUID: DataConvertible { |
185 | | - |
186 | | - public init?(data: Data) { |
187 | | - |
188 | | - guard data.count == UUID.length else { return nil } |
| 130 | +extension UUID: CustomReflectable { |
| 131 | + public var customMirror: Mirror { |
| 132 | + let c : [(label: String?, value: Any)] = [] |
| 133 | + let m = Mirror(self, children:c, displayStyle: .struct) |
| 134 | + return m |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +// MARK: - Codable |
| 139 | + |
| 140 | +extension UUID: Codable { |
| 141 | + public init(from decoder: Decoder) throws { |
| 142 | + let container = try decoder.singleValueContainer() |
| 143 | + let uuidString = try container.decode(String.self) |
| 144 | + |
| 145 | + guard let uuid = UUID(uuidString: uuidString) else { |
| 146 | + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, |
| 147 | + debugDescription: "Attempted to decode UUID from invalid UUID string.")) |
| 148 | + } |
189 | 149 |
|
190 | | - self.init(bytes: (data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15])) |
| 150 | + self = uuid |
191 | 151 | } |
192 | 152 |
|
193 | | - public func toData() -> Data { |
194 | | - |
195 | | - return Data(bytes: [bytes.0, bytes.1, bytes.2, bytes.3, bytes.4, bytes.5, bytes.6, bytes.7, bytes.8, bytes.9, bytes.10, bytes.11, bytes.12, bytes.13, bytes.14, bytes.15]) |
| 153 | + public func encode(to encoder: Encoder) throws { |
| 154 | + var container = encoder.singleValueContainer() |
| 155 | + try container.encode(self.uuidString) |
196 | 156 | } |
197 | 157 | } |
198 | 158 |
|
199 | | -// MARK: - Private |
| 159 | +// MARK: - Supporting Types |
200 | 160 |
|
201 | | -#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) |
202 | | - private typealias POSIXUUIDStringType = uuid_string_t |
203 | | -#elseif os(Linux) |
204 | | - private typealias POSIXUUIDStringType = (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) |
205 | | -#endif |
| 161 | +public typealias uuid_t = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) |
| 162 | +public typealias uuid_string_t = (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) |
0 commit comments