{"id":16154821,"url":"https://github.com/remibardon/swift-prefixed-type","last_synced_at":"2025-04-07T00:37:39.012Z","repository":{"id":45871699,"uuid":"381475989","full_name":"RemiBardon/swift-prefixed-type","owner":"RemiBardon","description":"A type-safe, Codable struct for prefixed types","archived":false,"fork":false,"pushed_at":"2023-06-02T13:48:10.000Z","size":71,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-13T06:18:20.093Z","etag":null,"topics":["codable","lightweight","prefix","prefixed","refined","refined-types","swift","swift-package-manager","tests","uuid"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RemiBardon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-29T19:29:49.000Z","updated_at":"2021-11-30T22:11:29.000Z","dependencies_parsed_at":"2024-12-20T12:26:40.850Z","dependency_job_id":"3a7ea477-f530-401e-bea2-6da25400b0ba","html_url":"https://github.com/RemiBardon/swift-prefixed-type","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemiBardon%2Fswift-prefixed-type","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemiBardon%2Fswift-prefixed-type/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemiBardon%2Fswift-prefixed-type/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemiBardon%2Fswift-prefixed-type/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RemiBardon","download_url":"https://codeload.github.com/RemiBardon/swift-prefixed-type/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247574087,"owners_count":20960495,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codable","lightweight","prefix","prefixed","refined","refined-types","swift","swift-package-manager","tests","uuid"],"created_at":"2024-10-10T01:18:59.832Z","updated_at":"2025-04-07T00:37:38.987Z","avatar_url":"https://github.com/RemiBardon.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `Prefixed`: A type-safe, `Codable` `struct` for prefixed types\n\n[![Tests](https://github.com/RemiBardon/swift-prefixed-type/actions/workflows/test.yaml/badge.svg)](https://github.com/RemiBardon/swift-prefixed-type/actions/workflows/test.yaml)\n\n## 🤔 What is `Prefixed` for?\n\n`UUID`s are great, you can use them everywhere… but when you do so,\nit starts being hard to recognize where a `UUID` comes from.\n\nA common pattern is to add readable prefixes to the `UUID`s.\nThis way, you can have `user_ee505428-a17b-4935-b81c-266b81a63515`\nand `post_d58a3f88-0493-458d-bd4b-a6ca4a2cc98c` for example,\nmaking it easy to find which is which.\n\nWriting this library, I wanted to keep it very simple and straight-forward.\nI also wanted the `PrefixedUUID`s to be type-safe, meaning a `UUID` prefixed with `user_`\ncould not be used instead of a `UUID` prefixed by `post_`.\n\nAfter writing `PrefixedUUID`, I realized prefixed `UUID`s are just a subset\nof all the types we could want to prefix. That's why I made it more generic,\nby creating the `Prefixed` `struct`.\n\n## 🛠 Features\n\n\u003e These are the features of `PrefixedUUID`s, but you can say the same with any other prefixed type.\n\n- **Type safety:** `User.ID != Post.ID`, even though they are stored the same way\n- **`Codable`:** (`Encodable \u0026 Decodable`) conformance\n- **Practical:** `PrefixedUUID`s allow you to access the underlying `UUID` or the prefixed `String`,\n  without storing anything more in memory or requiring expensive computations.\n- **Convenient:** Foundation's `UUID` extensions make it easy to work with `PrefixedUUID`s\n- **Type inference:** Most of the time, you don't need to make associated types explicit\n- **Lightweight:** `PrefixedUUID`s take (almost) as little space in memory as `UUID`s do.\n  `String` prefixes are stored once ever and dashes in the `UUID` are not stored.\n  The only thing that's stored for each `PrefixedUUID` is a `UUID` (which directly stores bytes).\n- **Case (in)sensitive:** By default, prefixes are case sensitive, but with a simple option,\n  you can choose for a prefix to be case insensitive.\n- **Debugging:** Failing to decode a `Prefixed` type shows a human-readable error:\n  - `\"'usr_abcdef' is not prefixed by 'user_'\"`\n  - `\"'USR_MONPQR' is not prefixed by 'user_' (case insensitive)\"`\n  - `\"user_ABCD\"` with a `Prefixed` `Int` =\u003e \u003ccode\u003e\"'ABCD' is not a valid \\`Int\\`\"\u003c/code\u003e\n  - `\"user_56C68C54\"` with a `Prefixed` `UUID` =\u003e \u003ccode\u003e\"'56C68C54' is not a valid \\`UUID\\`\"\u003c/code\u003e\n\n## 📦 Installation\n\n### Using `Package.swift` in another Swift Package\n\nTo use this package in a project, import the `\"prefixed-uuid\"` package like so:\n\n```swift\ndependencies: [\n\t// Other dependencies\n\t.package(\n\t\tname: \"prefixed\",\n\t\turl: \"https://github.com/RemiBardon/swift-prefixed-type\",\n\t\t.upToNextMajor(from: \"2.0.0\")\n\t),\n],\n```\n\nThen add it to your target like so:\n\n```swift\ntargets: [\n\t// ...\n\t.target(\n\t\tname: \"\u003cYourTarget\u003e\",\n\t\tdependencies: [\n\t\t\t// Other dependencies\n\t\t\t.product(name: \"Prefixed\", package: \"prefixed\"),\n\t\t]\n\t),\n\t// ...\n]\n```\n\n### In a full project\n\nTo add `Prefixed` to your project, go to your project's configuration,\nthen go to the \u003ckbd\u003eSwift Packages\u003c/kbd\u003e tab, click \u003ckbd\u003e+\u003c/kbd\u003e and follow XCode's instructions\n\u003csmall\u003e(Assuming you use XCode)\u003c/small\u003e. When you're asked for a URL, enter\n\u003chttps://github.com/RemiBardon/swift-prefixed-type\u003e.\n\n## 🧑‍💻 Usage\n\n\u003e The following uses `PrefixedUUID`s, but you can use `Prefixed\u003cPrefix, Base\u003e` instead if you want.\n\nFirst, create a type conforming to `PrefixProtocol`:\n\n```swift\nstruct UserIDPrefix: PrefixProtocol {\n\tstatic var prefix: String { \"user_\" }\n}\n```\n\nIf you want the prefix to be case-insensitive, you can override the default (`true`) value:\n\n```swift\nstruct CaseInsensitiveUserIDPrefix: PrefixProtocol {\n\tstatic var prefix: String { \"lower_user_\" }\n\tstatic var isCaseSensitive: Bool { false }\n}\n```\n\nThen, use your new type as you would normally do:\n\n```swift\nstruct User: Codable, Identifiable {\n\ttypealias ID = PrefixedUUID\u003cUserIDPrefix\u003e\n\tlet id: ID\n}\n```\n\n\u003e `Identifiable` is not necessary, it's just here as a good practice.\n\u003e `Codable` is not necessary either, but you can use it: `PrefixedUUID` conforms to `Codable`.\n\nThere are many ways to create a `PrefixedUUID`:\n\n- Using the verbose initializer:\n  \n  ```swift\n  let prefixedUUID = PrefixedUUID\u003cUserIDPrefix\u003e(uuid: UUID())\n  ```\n  \n- Using the default value (`UUID()`):\n  \n  ```swift\n  let prefixedUUID = PrefixedUUID\u003cUserIDPrefix\u003e()\n  ```\n  \n- Using the convenient `UUID` extensions:\n  \n  ```swift\n  let prefixedUUID = UUID().prefixed(by: UserIDPrefix.self)\n  ```\n  \n- The compiler can infer the type of your `UUIDPrefix`, so most of the time you just have to use `.prefixed()`:\n  \n  ```swift\n  let prefixedUUID: PrefixedUUID\u003cUserIDPrefix\u003e = UUID().prefixed()\n  ```\n\n## ⚠️ Warnings\n\n- Do not make an existing `struct` conform to `PrefixProtocol`:\n  `PrefixProtocol` sets custom `String` and debug descriptions which would override the one you expect.\n\n## ❌ Major versions migrations\n\n### From `1.X.X` to `2.X.X`\n\n- Package has been renamed from `prefixed-uuid` to `prefixed`\n- Package library has been renamed from `PrefixedUUID` to `Prefixed`\n- `UUIDPrefix` has been renamed to `PrefixProtocol`\n\t- `UUIDPrefix.uuidPrefix` has been renamed to `PrefixProtocol.prefix`\n\t- `UUIDPrefix.uuidPrefixIsCaseSensitive` has been renamed to `PrefixProtocol.isCaseSensitive`\n\n## 🗺 Roadmap\n\nAs you would expect from a package this small, it is not actively developed.\nHowever, I still have a few things to add:\n\n- [x] Generic `Prefixed` `struct`, to be `UUID`-independent\n- [x] Swift documentation comments, to make the package more understandable\n- [x] Continuous Integration, to be sure the package runs in all environments\n- [ ] Documentation page\n- [ ] (Installation guides for older Swift Package Manager versions)\n- [ ] (CONTRIBUTING guidelines)\n\n## ⚖️ License\n\nThis package is provided under MIT License. For more information, see [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremibardon%2Fswift-prefixed-type","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremibardon%2Fswift-prefixed-type","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremibardon%2Fswift-prefixed-type/lists"}