Skip to content

Instantly share code, notes, and snippets.

@ts95
Created January 5, 2023 09:25
Show Gist options
  • Save ts95/166eaf0387f13e9f67b59fbbdfc25cea to your computer and use it in GitHub Desktop.
Save ts95/166eaf0387f13e9f67b59fbbdfc25cea to your computer and use it in GitHub Desktop.
Swift port of the ID generator used in Firebase Firestore
import Foundation
class AutoId {
private init() {}
static func newId() -> String {
// Alphanumeric characters
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
// The largest byte value that is a multiple of `char.length`.
let maxMultiple = Int(256 / chars.count) * chars.count
assert(
0 < maxMultiple && maxMultiple < 256,
"Expect maxMultiple to be (0, 256), but got \(maxMultiple)"
)
var autoId = ""
let targetLength = 20
while autoId.count < targetLength {
let bytes = Self.randomBytes(40)
for i in 0..<bytes.count {
// Only accept values that are [0, maxMultiple), this ensures they can
// be evenly mapped to indices of `chars` via a modulo operation.
if autoId.count < targetLength && bytes[i] < maxMultiple {
autoId += String(chars[chars.index(chars.startIndex, offsetBy: Int(bytes[i]) % chars.count)])
}
}
}
assert(autoId.count == targetLength, "Invalid auto ID: \(autoId)")
return autoId
}
private static func randomBytes(_ count: Int) -> [UInt8] {
var bytes = [UInt8](repeating: 0, count: count)
let _ = SecRandomCopyBytes(kSecRandomDefault, count, &bytes)
return bytes
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment