Refactoring
This commit is contained in:
parent
9d45ad0a3a
commit
fed2b36d19
|
@ -7,44 +7,67 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public typealias ulid_t = uuid_t
|
||||
|
||||
public struct ULID {
|
||||
|
||||
public let ulidString: String
|
||||
public private(set) var ulid: ulid_t = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
|
||||
public init(ulid: ulid_t) {
|
||||
self.ulid = ulid
|
||||
}
|
||||
|
||||
public init(timestamp: Date = Date()) {
|
||||
let now = UInt64(timestamp.timeIntervalSince1970 * 1000.0)
|
||||
let timestampBase32 = withUnsafePointer(to: now.bigEndian) { (pointer) -> String in
|
||||
var data = Data(bytes: pointer, count: 8)
|
||||
data.insert(contentsOf: [0x00, 0x00], at: 0)
|
||||
return String(data.base32EncodedString().suffix(10))
|
||||
withUnsafeMutableBytes(of: &ulid) { (buffer) in
|
||||
var millisec = UInt64(timestamp.timeIntervalSince1970 * 1000.0).bigEndian
|
||||
withUnsafeBytes(of: &millisec) {
|
||||
for i in 0 ..< 6 {
|
||||
buffer[i] = $0[2 + i]
|
||||
}
|
||||
}
|
||||
let range = UInt8.min ... .max
|
||||
for i in 6 ..< 16 {
|
||||
buffer[i] = UInt8.random(in: range)
|
||||
}
|
||||
}
|
||||
let randomness = (0 ..< 16).map { _ in
|
||||
Base32.crockfordsEncodingTable[Int.random(in: 0 ..< Base32.crockfordsEncodingTable.count)]
|
||||
}
|
||||
self.ulidString = timestampBase32 + String(randomness)
|
||||
}
|
||||
|
||||
public init(ulidString string: String) {
|
||||
self.ulidString = string
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ULID {
|
||||
|
||||
private func decodeTimestamp() -> Date? {
|
||||
let base32 = "000000" + String(self.ulidString.prefix(10))
|
||||
guard let data = Data(base32Encoded: base32) else {
|
||||
public init?(ulidData data: Data) {
|
||||
guard data.count == 16 else {
|
||||
return nil
|
||||
}
|
||||
return data.suffix(8).withUnsafeBytes { (pointer: UnsafePointer<UInt64>) in
|
||||
Date(timeIntervalSince1970: TimeInterval(pointer.pointee.bigEndian) / 1000.0)
|
||||
withUnsafeMutableBytes(of: &ulid) {
|
||||
$0.copyBytes(from: data)
|
||||
}
|
||||
}
|
||||
|
||||
public init?(ulidString string: String) {
|
||||
guard string.count == 26, let data = Data(base32Encoded: "000000" + string) else {
|
||||
return nil
|
||||
}
|
||||
self.init(ulidData: data.dropFirst(4))
|
||||
}
|
||||
|
||||
public var ulidData: Data {
|
||||
return withUnsafeBytes(of: ulid) {
|
||||
return Data(buffer: $0.bindMemory(to: UInt8.self))
|
||||
}
|
||||
}
|
||||
|
||||
public var ulidString: String {
|
||||
return String((Data(count: 4) + ulidData).base32EncodedString().dropFirst(6))
|
||||
}
|
||||
|
||||
public var timestamp: Date {
|
||||
// TODO: Validate on `init`
|
||||
return self.decodeTimestamp()!
|
||||
return withUnsafeBytes(of: ulid) { (buffer) in
|
||||
var millisec: UInt64 = 0
|
||||
withUnsafeMutableBytes(of: &millisec) {
|
||||
for i in 0 ..< 6 {
|
||||
$0[2 + i] = buffer[i]
|
||||
}
|
||||
}
|
||||
return Date(timeIntervalSince1970: TimeInterval(millisec.bigEndian) / 1000.0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue