Skip to content

Releases: RougeWare/ContextuallyUniqueIdentifier

1.2 • Renamed this package

16 May 05:54
ede27fa
Compare
Choose a tag to compare

This was originally named AppUniqueIdentifier, because the initial use involved a stateless, single-user app.

However, when thinking of this package outside that usecase, it's obvious that the real concept isn't per-app, but per-context. That context could be an app, or a user, or a document, or a single session, etc.

So, it's been renamed ContextuallyUniqueIdentifier, or COID.
Choosing COID because CUID was already taken.

This release also includes a compatibility library named AppUniqueIdentifier so previous users can continue using this without interruption, and a typealias to match. They'll just receive a deprecation notice. This support will continue until version 2, if that ever happens

1.1 • Added regions!

11 Oct 04:45
f7385ee
Compare
Choose a tag to compare

Regions introduce some semantic meaning to certain AUIDs!

General Use

These are the same AUIDs you're used to. They work just like they always have

Unused

These are reserved for future use, in case We wanna introduce new semantic regions in a backwards-compatible way. You cannot use IDs in this region.

Private Use

This region of AUIDs is the reason for this update! The concept is that, sometimes, you might have special values that still require an AUID. For example, if you have a list of people where one is a special value meaning "add a new person", you might give that a private-use AUID.

These are a small amount of IDs which are manually and specifically requested. Like the Unicode private-use plane, this region of IDs has no specific intent/meaning, and allows the developer to ascribe specific meanings to each. The small size of this range means that there are no requests to generate a "next" one, and each specific one should be carefully chosen by the developer.

Error

There is exactly one AUID in this range. It simply signifies that a significant problem has occurred. This is useful when you want to know there's an error state, but are in a situation where throw/catch and crashing are not possible/desired

Layout

For a sense of how these regions are laid out, here's a not-to-scale diagram:

✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒
🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒
🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒
🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒 🔒
🔒 🔒 🔒 🔒 🔒 🔒 🔒 *️⃣ *️⃣ ❗️

This update comes with various APIs regarding these regions.

1.0 - MVP

25 Nov 05:52
f97e471
Compare
Choose a tag to compare

An AUID is an identifier which is unique to a runtime andor save data. While UUID is good for general use, this is good specifically for a single session.

This is only guaranteed to be unique per-session if used correctly. Any further uniqueness is not guaranteed.

The current implementation simply uses positive integers. However, it's good practice to treat this as an opaque type in case the implementation changes in the future.

Creating a new ID

To create a new ID, you must call .next(), for a new ID to be generated and returned:

struct Person: Identifiable, Codable {
    var id: AppUniqueIdentifier = .next()
    let name: String
}


let person = Person(name: "Dax")

Encoding & Decoding an ID

AUIDs are encoded as simple integers. One can expect the above Person instance to be encoded like this:

{
    "id": 7,
    "name": "Dax"
}

AUID has built-in encoding and decoding, so nothing special need be done. Just use any Swift encoder/decoder, like this:

let jsonData = try JSONEncoder().encode(person)
let decodedPerson = try JSONDecoder().decode(Person.self, from: jsonData)
assert(person == decodedPerson)

Decoding an AUID assures that the ID is not used in any future calls to .next(). Encoding an AUID has no special behavior.

Stringification

To create a string form of a given ID, simply call .description, or pass it to String(describing:):

Text(verbatim: person.id.description)

If you have a string form of an ID already (e.g. one you got from calling .description), you may transform it back into an AppUniqueIdentifier with the .init(_:) initializer. Only valid ID strings will result in a new value; invalid ones result in nil. The subsystem will ensure that this ID is not returned by .next()

When you're done with an ID

If you no longer wish to use an ID (for example, the concept it was tracking has been deleted by the user), then you may pass it to AppUniqueIdentifier.recycle(id:):

mutating func remove(_ person: Person) {
    self.people.remove(person)
    AppUniqueIdentifier.recycle(id: person.id)
}