├── .cargo └── config.toml ├── .github ├── codecov.yml ├── renovate.json └── workflows │ ├── ci.yml │ ├── coverage.yml │ ├── docs.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── crates ├── integration-tests │ ├── Cargo.toml │ ├── outputs │ │ ├── schema-rust-with-replace.rs │ │ ├── schema-rust.rs │ │ ├── typed-uuid-openapi.json │ │ ├── typed-uuid-rust.rs │ │ └── typed-uuid-schema.json │ └── src │ │ ├── json_schema.rs │ │ ├── lib.rs │ │ └── proptests.rs └── newtype-uuid │ ├── CHANGELOG.md │ ├── Cargo.toml │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── README.tpl │ ├── build.rs │ └── src │ └── lib.rs ├── release.toml └── scripts ├── commands.sh ├── fix-readmes.awk └── regenerate-readmes.sh /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xfmt = "fmt -- --config imports_granularity=Crate --config group_imports=One" 3 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | informational: true 6 | patch: 7 | default: 8 | target: 0% 9 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>oxidecomputer/renovate-config", 5 | "local>oxidecomputer/renovate-config//rust/autocreate", 6 | "local>oxidecomputer/renovate-config//actions/pin" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | 7 | name: CI 8 | 9 | jobs: 10 | lint: 11 | name: Lint 12 | runs-on: ubuntu-latest 13 | env: 14 | RUSTFLAGS: -D warnings 15 | steps: 16 | - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 17 | - uses: dtolnay/rust-toolchain@stable 18 | with: 19 | components: rustfmt, clippy 20 | - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 21 | - name: Lint (clippy) 22 | run: cargo clippy --all-features --all-targets 23 | - name: Lint (rustfmt) 24 | run: cargo xfmt --check 25 | - name: Run rustdoc 26 | env: 27 | RUSTC_BOOTSTRAP: 1 # for feature(doc_cfg) 28 | RUSTDOCFLAGS: -Dwarnings --cfg doc_cfg 29 | run: cargo doc --all-features --workspace 30 | - name: Check for differences 31 | run: git diff --exit-code 32 | 33 | build-and-test: 34 | name: Build and test 35 | runs-on: ${{ matrix.os }} 36 | strategy: 37 | matrix: 38 | os: [ubuntu-latest] 39 | # 1.67 is the MSRV 40 | rust-version: ["1.67", stable] 41 | fail-fast: false 42 | env: 43 | RUSTFLAGS: -D warnings 44 | steps: 45 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 46 | - uses: dtolnay/rust-toolchain@master 47 | with: 48 | toolchain: ${{ matrix.rust-version }} 49 | - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2 50 | - uses: taiki-e/install-action@cargo-hack 51 | - uses: taiki-e/install-action@nextest 52 | - name: Build 53 | run: ./scripts/commands.sh build 54 | - name: Test 55 | run: ./scripts/commands.sh nextest 56 | - name: Run extended tests (only on stable) 57 | if: matrix.rust-version == 'stable' 58 | run: ./scripts/commands.sh nextest-all-features 59 | - name: Run doctests 60 | if: matrix.rust-version == 'stable' 61 | run: ./scripts/commands.sh doctest 62 | 63 | no-std: 64 | name: Build no_std for ${{ matrix.target }} 65 | runs-on: ubuntu-latest 66 | strategy: 67 | matrix: 68 | target: 69 | - thumbv7m-none-eabi 70 | rust-version: [stable] 71 | fail-fast: false 72 | steps: 73 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 74 | - uses: dtolnay/rust-toolchain@master 75 | with: 76 | toolchain: ${{ matrix.rust-version }} 77 | targets: ${{ matrix.target }} 78 | - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2 79 | - uses: taiki-e/install-action@cargo-hack 80 | - run: ./scripts/commands.sh build-no-std --target ${{ matrix.target }} 81 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: Test coverage 10 | 11 | jobs: 12 | coverage: 13 | name: Collect test coverage 14 | runs-on: ubuntu-latest 15 | # nightly rust might break from time to time 16 | continue-on-error: true 17 | env: 18 | RUSTFLAGS: -D warnings 19 | steps: 20 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 21 | - uses: dtolnay/rust-toolchain@nightly # Use nightly to get access to coverage --doc 22 | with: 23 | components: llvm-tools-preview 24 | - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2 25 | - name: Install latest nextest release 26 | uses: taiki-e/install-action@nextest 27 | - name: Install cargo-llvm-cov 28 | uses: taiki-e/install-action@cargo-llvm-cov 29 | 30 | - name: Collect coverage data 31 | run: ./scripts/commands.sh coverage 32 | - name: Upload coverage data to codecov 33 | uses: codecov/codecov-action@f30e4959ba63075080d4f7f90cacc18d9f3fafd7 # v4 34 | with: 35 | files: lcov.info, lcov-doctest.info 36 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | name: Docs 7 | 8 | jobs: 9 | docs: 10 | name: Build and deploy documentation 11 | concurrency: ci-${{ github.ref }} 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 15 | - uses: dtolnay/rust-toolchain@stable 16 | - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2 17 | - name: Build rustdoc 18 | env: 19 | RUSTC_BOOTSTRAP: 1 # for feature(doc_cfg) 20 | RUSTDOCFLAGS: -Dwarnings --cfg doc_cfg 21 | run: cargo doc --all-features --workspace --exclude integration-tests 22 | - name: Organize 23 | run: | 24 | rm -rf target/gh-pages 25 | mkdir target/gh-pages 26 | mv target/doc target/gh-pages/rustdoc 27 | touch target/gh-pages/.nojekyll 28 | - name: Deploy 29 | uses: JamesIves/github-pages-deploy-action@releases/v4 30 | with: 31 | branch: gh-pages 32 | folder: target/gh-pages 33 | single-commit: true 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # adapted from https://github.com/taiki-e/cargo-hack/blob/main/.github/workflows/release.yml 2 | 3 | name: Publish release 4 | on: 5 | push: 6 | tags: 7 | - "*" 8 | 9 | jobs: 10 | create-release: 11 | if: github.repository_owner == 'oxidecomputer' 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4 15 | with: 16 | persist-credentials: false 17 | - name: Install Rust 18 | uses: dtolnay/rust-toolchain@stable 19 | - run: cargo publish -p newtype-uuid 20 | env: 21 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 22 | - uses: taiki-e/create-gh-release-action@72d65cee1f8033ef0c8b5d79eaf0c45c7c578ce3 # v1 23 | with: 24 | changelog: CHANGELOG.md 25 | title: newtype-uuid $version 26 | branch: main 27 | prefix: newtype-uuid 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.2.2] - 2025-05-24 4 | 5 | ### Added 6 | 7 | Added the following implementations: 8 | 9 | - `AsRef<[u8]>` for `TypedUuid`. 10 | - `From> for Vec`. 11 | 12 | ## [1.2.1] - 2025-01-14 13 | 14 | Updated MSRV in readme. 15 | 16 | ## [1.2.0] - 2025-01-14 17 | 18 | ### Added 19 | 20 | - New, optional feature `proptest1` enables support for generating random instances of UUIDs. Currently, v4 UUIDs are always generated. 21 | 22 | ### Changed 23 | 24 | - MSRV updated to Rust 1.67. 25 | 26 | ## [1.1.3] - 2024-11-07 27 | 28 | ### Added 29 | 30 | - Add a `Default` implementation for `TypedUuid`. This implementation resolves 31 | to `TypedUuid::nil()`. 32 | 33 | ## [1.1.2] - 2024-10-07 34 | 35 | ### Added 36 | 37 | More const constructors for typed UUIDs, mirrored from the `uuid` crate: `from_fields`, 38 | `from_fields_le`, `from_u128`, `from_u128_le`, `from_u64_pair`, `from_bytes`, and `from_bytes_le`. 39 | 40 | ### Fixed 41 | 42 | Correct doc for `as_untyped_uuid`. Thanks [@Dr-Emann](https://github.com/Dr-Emann) for your first contribution! 43 | 44 | ## [1.1.1] - 2024-10-07 45 | 46 | (This version was not released due to a publishing issue.) 47 | 48 | ## [1.1.0] - 2024-04-12 49 | 50 | ### Added 51 | 52 | - `TypedUuid::nil()` and `max()` constructors. 53 | - `TypedUuid` is now `#[repr(transparent)]`. 54 | 55 | ### Changed 56 | 57 | - MSRV updated to Rust 1.61. 58 | 59 | ## [1.0.1] - 2024-02-15 60 | 61 | ### Breaking changes 62 | 63 | - `GenericUuid::to_generic_uuid` has been renamed to `GenericUuid::into_generic_uuid`. 64 | 65 | ### Changed 66 | 67 | - Added `#[must_use]` annotations to constructors. 68 | 69 | ## [1.0.0] - 2024-02-15 70 | 71 | (This version was not published due to a CI issue.) 72 | 73 | ## [0.3.0] - 2024-02-02 74 | 75 | ### Breaking changes 76 | 77 | - `TypedUuidTag::try_new` returns a new `TagError` type rather than just a raw `&'static str`. 78 | 79 | ### Changed 80 | 81 | - `TypedUuidTag::as_str` is now a `const fn`. 82 | 83 | ## [0.2.1] - 2024-02-02 84 | 85 | Documentation improvements. 86 | 87 | ## [0.2.0] - 2024-02-01 88 | 89 | ### Breaking changes 90 | 91 | - `TypedUuidTag`s are now required to be valid ASCII identifiers, with hyphens also supported. 92 | 93 | ### Misc 94 | 95 | - Added `#[forbid(unsafe_code)]`. Thanks [Robert Lynch](https://github.com/rob0rt) for the contribution! 96 | 97 | ## [0.1.0] - 2024-01-30 98 | 99 | Initial release. 100 | 101 | [1.2.2]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.2.2 102 | [1.2.1]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.2.1 103 | [1.2.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.2.0 104 | [1.1.3]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.1.3 105 | [1.1.2]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.1.2 106 | [1.1.1]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.1.1 107 | [1.1.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.1.0 108 | [1.0.1]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.0.1 109 | [1.0.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-1.0.0 110 | [0.3.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-0.3.0 111 | [0.2.1]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-0.2.1 112 | [0.2.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-0.2.0 113 | [0.1.0]: https://github.com/oxidecomputer/newtype-uuid/releases/newtype-uuid-0.1.0 114 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "once_cell", 28 | "version_check", 29 | "zerocopy", 30 | ] 31 | 32 | [[package]] 33 | name = "android-tzdata" 34 | version = "0.1.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 37 | 38 | [[package]] 39 | name = "android_system_properties" 40 | version = "0.1.5" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 43 | dependencies = [ 44 | "libc", 45 | ] 46 | 47 | [[package]] 48 | name = "async-stream" 49 | version = "0.3.6" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 52 | dependencies = [ 53 | "async-stream-impl", 54 | "futures-core", 55 | "pin-project-lite", 56 | ] 57 | 58 | [[package]] 59 | name = "async-stream-impl" 60 | version = "0.3.6" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 63 | dependencies = [ 64 | "proc-macro2", 65 | "quote", 66 | "syn", 67 | ] 68 | 69 | [[package]] 70 | name = "async-trait" 71 | version = "0.1.85" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" 74 | dependencies = [ 75 | "proc-macro2", 76 | "quote", 77 | "syn", 78 | ] 79 | 80 | [[package]] 81 | name = "atomic-waker" 82 | version = "1.1.2" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 85 | 86 | [[package]] 87 | name = "autocfg" 88 | version = "1.4.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 91 | 92 | [[package]] 93 | name = "backtrace" 94 | version = "0.3.74" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 97 | dependencies = [ 98 | "addr2line", 99 | "cfg-if", 100 | "libc", 101 | "miniz_oxide", 102 | "object", 103 | "rustc-demangle", 104 | "windows-targets", 105 | ] 106 | 107 | [[package]] 108 | name = "base64" 109 | version = "0.22.1" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 112 | 113 | [[package]] 114 | name = "bitflags" 115 | version = "2.8.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 118 | 119 | [[package]] 120 | name = "block-buffer" 121 | version = "0.10.4" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 124 | dependencies = [ 125 | "generic-array", 126 | ] 127 | 128 | [[package]] 129 | name = "bumpalo" 130 | version = "3.14.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" 133 | 134 | [[package]] 135 | name = "byteorder" 136 | version = "1.5.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 139 | 140 | [[package]] 141 | name = "bytes" 142 | version = "1.9.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 145 | 146 | [[package]] 147 | name = "camino" 148 | version = "1.1.9" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" 151 | dependencies = [ 152 | "serde", 153 | ] 154 | 155 | [[package]] 156 | name = "cc" 157 | version = "1.2.9" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" 160 | dependencies = [ 161 | "shlex", 162 | ] 163 | 164 | [[package]] 165 | name = "cfg-if" 166 | version = "1.0.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 169 | 170 | [[package]] 171 | name = "chrono" 172 | version = "0.4.39" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" 175 | dependencies = [ 176 | "android-tzdata", 177 | "iana-time-zone", 178 | "num-traits", 179 | "serde", 180 | "windows-targets", 181 | ] 182 | 183 | [[package]] 184 | name = "console" 185 | version = "0.15.10" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" 188 | dependencies = [ 189 | "encode_unicode", 190 | "libc", 191 | "once_cell", 192 | "unicode-width", 193 | "windows-sys 0.59.0", 194 | ] 195 | 196 | [[package]] 197 | name = "core-foundation-sys" 198 | version = "0.8.7" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 201 | 202 | [[package]] 203 | name = "cpufeatures" 204 | version = "0.2.16" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 207 | dependencies = [ 208 | "libc", 209 | ] 210 | 211 | [[package]] 212 | name = "crossbeam-channel" 213 | version = "0.5.15" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 216 | dependencies = [ 217 | "crossbeam-utils", 218 | ] 219 | 220 | [[package]] 221 | name = "crossbeam-utils" 222 | version = "0.8.21" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 225 | 226 | [[package]] 227 | name = "crypto-common" 228 | version = "0.1.6" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 231 | dependencies = [ 232 | "generic-array", 233 | "typenum", 234 | ] 235 | 236 | [[package]] 237 | name = "debug-ignore" 238 | version = "1.0.5" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "ffe7ed1d93f4553003e20b629abe9085e1e81b1429520f897f8f8860bc6dfc21" 241 | 242 | [[package]] 243 | name = "deranged" 244 | version = "0.3.11" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 247 | dependencies = [ 248 | "powerfmt", 249 | ] 250 | 251 | [[package]] 252 | name = "digest" 253 | version = "0.10.7" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 256 | dependencies = [ 257 | "block-buffer", 258 | "crypto-common", 259 | ] 260 | 261 | [[package]] 262 | name = "dirs-next" 263 | version = "2.0.0" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 266 | dependencies = [ 267 | "cfg-if", 268 | "dirs-sys-next", 269 | ] 270 | 271 | [[package]] 272 | name = "dirs-sys-next" 273 | version = "0.1.2" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 276 | dependencies = [ 277 | "libc", 278 | "redox_users", 279 | "winapi", 280 | ] 281 | 282 | [[package]] 283 | name = "dropshot" 284 | version = "0.10.1" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "a391eeedf8a75a188eb670327c704b7ab10eb2bb890e2ec0880dd21d609fb6e8" 287 | dependencies = [ 288 | "async-stream", 289 | "async-trait", 290 | "base64", 291 | "bytes", 292 | "camino", 293 | "chrono", 294 | "debug-ignore", 295 | "dropshot_endpoint", 296 | "form_urlencoded", 297 | "futures", 298 | "hostname 0.4.0", 299 | "http 0.2.12", 300 | "hyper", 301 | "indexmap", 302 | "multer", 303 | "openapiv3", 304 | "paste", 305 | "percent-encoding", 306 | "rustls", 307 | "rustls-pemfile", 308 | "schemars", 309 | "scopeguard", 310 | "serde", 311 | "serde_json", 312 | "serde_path_to_error", 313 | "serde_urlencoded", 314 | "sha1", 315 | "slog", 316 | "slog-async", 317 | "slog-bunyan", 318 | "slog-json", 319 | "slog-term", 320 | "tokio", 321 | "tokio-rustls", 322 | "toml", 323 | "uuid", 324 | "version_check", 325 | "waitgroup", 326 | ] 327 | 328 | [[package]] 329 | name = "dropshot_endpoint" 330 | version = "0.10.1" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "9058c9c7e4a6b378cd12e71dc155bb15d0d4f8e1e6039ce2cf0a7c0c81043e33" 333 | dependencies = [ 334 | "proc-macro2", 335 | "quote", 336 | "serde", 337 | "serde_tokenstream", 338 | "syn", 339 | ] 340 | 341 | [[package]] 342 | name = "dyn-clone" 343 | version = "1.0.17" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 346 | 347 | [[package]] 348 | name = "encode_unicode" 349 | version = "1.0.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" 352 | 353 | [[package]] 354 | name = "encoding_rs" 355 | version = "0.8.35" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 358 | dependencies = [ 359 | "cfg-if", 360 | ] 361 | 362 | [[package]] 363 | name = "equivalent" 364 | version = "1.0.1" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 367 | 368 | [[package]] 369 | name = "expectorate" 370 | version = "1.1.0" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "de6f19b25bdfa2747ae775f37cd109c31f1272d4e4c83095be0727840aa1d75f" 373 | dependencies = [ 374 | "console", 375 | "newline-converter", 376 | "similar", 377 | ] 378 | 379 | [[package]] 380 | name = "fnv" 381 | version = "1.0.7" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 384 | 385 | [[package]] 386 | name = "form_urlencoded" 387 | version = "1.2.1" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 390 | dependencies = [ 391 | "percent-encoding", 392 | ] 393 | 394 | [[package]] 395 | name = "futures" 396 | version = "0.3.31" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 399 | dependencies = [ 400 | "futures-channel", 401 | "futures-core", 402 | "futures-executor", 403 | "futures-io", 404 | "futures-sink", 405 | "futures-task", 406 | "futures-util", 407 | ] 408 | 409 | [[package]] 410 | name = "futures-channel" 411 | version = "0.3.31" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 414 | dependencies = [ 415 | "futures-core", 416 | "futures-sink", 417 | ] 418 | 419 | [[package]] 420 | name = "futures-core" 421 | version = "0.3.31" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 424 | 425 | [[package]] 426 | name = "futures-executor" 427 | version = "0.3.31" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 430 | dependencies = [ 431 | "futures-core", 432 | "futures-task", 433 | "futures-util", 434 | ] 435 | 436 | [[package]] 437 | name = "futures-io" 438 | version = "0.3.31" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 441 | 442 | [[package]] 443 | name = "futures-macro" 444 | version = "0.3.31" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 447 | dependencies = [ 448 | "proc-macro2", 449 | "quote", 450 | "syn", 451 | ] 452 | 453 | [[package]] 454 | name = "futures-sink" 455 | version = "0.3.31" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 458 | 459 | [[package]] 460 | name = "futures-task" 461 | version = "0.3.31" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 464 | 465 | [[package]] 466 | name = "futures-util" 467 | version = "0.3.31" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 470 | dependencies = [ 471 | "futures-channel", 472 | "futures-core", 473 | "futures-io", 474 | "futures-macro", 475 | "futures-sink", 476 | "futures-task", 477 | "memchr", 478 | "pin-project-lite", 479 | "pin-utils", 480 | "slab", 481 | ] 482 | 483 | [[package]] 484 | name = "generic-array" 485 | version = "0.14.7" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 488 | dependencies = [ 489 | "typenum", 490 | "version_check", 491 | ] 492 | 493 | [[package]] 494 | name = "getrandom" 495 | version = "0.2.15" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 498 | dependencies = [ 499 | "cfg-if", 500 | "libc", 501 | "wasi", 502 | ] 503 | 504 | [[package]] 505 | name = "gimli" 506 | version = "0.31.1" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 509 | 510 | [[package]] 511 | name = "h2" 512 | version = "0.3.26" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 515 | dependencies = [ 516 | "bytes", 517 | "fnv", 518 | "futures-core", 519 | "futures-sink", 520 | "futures-util", 521 | "http 0.2.12", 522 | "indexmap", 523 | "slab", 524 | "tokio", 525 | "tokio-util", 526 | "tracing", 527 | ] 528 | 529 | [[package]] 530 | name = "hashbrown" 531 | version = "0.13.2" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 534 | dependencies = [ 535 | "ahash", 536 | ] 537 | 538 | [[package]] 539 | name = "hashbrown" 540 | version = "0.15.2" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 543 | 544 | [[package]] 545 | name = "heck" 546 | version = "0.4.1" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 549 | 550 | [[package]] 551 | name = "hermit-abi" 552 | version = "0.4.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 555 | 556 | [[package]] 557 | name = "hostname" 558 | version = "0.3.1" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" 561 | dependencies = [ 562 | "libc", 563 | "match_cfg", 564 | "winapi", 565 | ] 566 | 567 | [[package]] 568 | name = "hostname" 569 | version = "0.4.0" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" 572 | dependencies = [ 573 | "cfg-if", 574 | "libc", 575 | "windows", 576 | ] 577 | 578 | [[package]] 579 | name = "http" 580 | version = "0.2.12" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 583 | dependencies = [ 584 | "bytes", 585 | "fnv", 586 | "itoa", 587 | ] 588 | 589 | [[package]] 590 | name = "http" 591 | version = "1.2.0" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 594 | dependencies = [ 595 | "bytes", 596 | "fnv", 597 | "itoa", 598 | ] 599 | 600 | [[package]] 601 | name = "http-body" 602 | version = "0.4.6" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 605 | dependencies = [ 606 | "bytes", 607 | "http 0.2.12", 608 | "pin-project-lite", 609 | ] 610 | 611 | [[package]] 612 | name = "httparse" 613 | version = "1.9.5" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 616 | 617 | [[package]] 618 | name = "httpdate" 619 | version = "1.0.3" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 622 | 623 | [[package]] 624 | name = "hyper" 625 | version = "0.14.32" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 628 | dependencies = [ 629 | "bytes", 630 | "futures-channel", 631 | "futures-core", 632 | "futures-util", 633 | "h2", 634 | "http 0.2.12", 635 | "http-body", 636 | "httparse", 637 | "httpdate", 638 | "itoa", 639 | "pin-project-lite", 640 | "socket2", 641 | "tokio", 642 | "tower-service", 643 | "tracing", 644 | "want", 645 | ] 646 | 647 | [[package]] 648 | name = "iana-time-zone" 649 | version = "0.1.61" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 652 | dependencies = [ 653 | "android_system_properties", 654 | "core-foundation-sys", 655 | "iana-time-zone-haiku", 656 | "js-sys", 657 | "wasm-bindgen", 658 | "windows-core", 659 | ] 660 | 661 | [[package]] 662 | name = "iana-time-zone-haiku" 663 | version = "0.1.2" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 666 | dependencies = [ 667 | "cc", 668 | ] 669 | 670 | [[package]] 671 | name = "indexmap" 672 | version = "2.7.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 675 | dependencies = [ 676 | "equivalent", 677 | "hashbrown 0.15.2", 678 | "serde", 679 | ] 680 | 681 | [[package]] 682 | name = "integration-tests" 683 | version = "0.1.0" 684 | dependencies = [ 685 | "dropshot", 686 | "expectorate", 687 | "newtype-uuid", 688 | "prettyplease", 689 | "proptest", 690 | "schemars", 691 | "serde", 692 | "serde_json", 693 | "syn", 694 | "test-strategy", 695 | "typify", 696 | "uuid", 697 | ] 698 | 699 | [[package]] 700 | name = "is-terminal" 701 | version = "0.4.13" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" 704 | dependencies = [ 705 | "hermit-abi", 706 | "libc", 707 | "windows-sys 0.52.0", 708 | ] 709 | 710 | [[package]] 711 | name = "itoa" 712 | version = "1.0.14" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 715 | 716 | [[package]] 717 | name = "js-sys" 718 | version = "0.3.77" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 721 | dependencies = [ 722 | "once_cell", 723 | "wasm-bindgen", 724 | ] 725 | 726 | [[package]] 727 | name = "lazy_static" 728 | version = "1.5.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 731 | 732 | [[package]] 733 | name = "libc" 734 | version = "0.2.169" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 737 | 738 | [[package]] 739 | name = "libredox" 740 | version = "0.1.3" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 743 | dependencies = [ 744 | "bitflags", 745 | "libc", 746 | ] 747 | 748 | [[package]] 749 | name = "lock_api" 750 | version = "0.4.12" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 753 | dependencies = [ 754 | "autocfg", 755 | "scopeguard", 756 | ] 757 | 758 | [[package]] 759 | name = "log" 760 | version = "0.4.25" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 763 | 764 | [[package]] 765 | name = "match_cfg" 766 | version = "0.1.0" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" 769 | 770 | [[package]] 771 | name = "memchr" 772 | version = "2.7.4" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 775 | 776 | [[package]] 777 | name = "mime" 778 | version = "0.3.17" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 781 | 782 | [[package]] 783 | name = "miniz_oxide" 784 | version = "0.8.3" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 787 | dependencies = [ 788 | "adler2", 789 | ] 790 | 791 | [[package]] 792 | name = "mio" 793 | version = "1.0.3" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 796 | dependencies = [ 797 | "libc", 798 | "wasi", 799 | "windows-sys 0.52.0", 800 | ] 801 | 802 | [[package]] 803 | name = "multer" 804 | version = "3.1.0" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" 807 | dependencies = [ 808 | "bytes", 809 | "encoding_rs", 810 | "futures-util", 811 | "http 1.2.0", 812 | "httparse", 813 | "memchr", 814 | "mime", 815 | "spin", 816 | "version_check", 817 | ] 818 | 819 | [[package]] 820 | name = "newline-converter" 821 | version = "0.3.0" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" 824 | dependencies = [ 825 | "unicode-segmentation", 826 | ] 827 | 828 | [[package]] 829 | name = "newtype-uuid" 830 | version = "1.2.2" 831 | dependencies = [ 832 | "proptest", 833 | "schemars", 834 | "serde", 835 | "uuid", 836 | ] 837 | 838 | [[package]] 839 | name = "num-conv" 840 | version = "0.1.0" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 843 | 844 | [[package]] 845 | name = "num-traits" 846 | version = "0.2.19" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 849 | dependencies = [ 850 | "autocfg", 851 | ] 852 | 853 | [[package]] 854 | name = "num_threads" 855 | version = "0.1.7" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" 858 | dependencies = [ 859 | "libc", 860 | ] 861 | 862 | [[package]] 863 | name = "object" 864 | version = "0.36.7" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 867 | dependencies = [ 868 | "memchr", 869 | ] 870 | 871 | [[package]] 872 | name = "once_cell" 873 | version = "1.20.2" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 876 | 877 | [[package]] 878 | name = "openapiv3" 879 | version = "2.0.0" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "cc02deea53ffe807708244e5914f6b099ad7015a207ee24317c22112e17d9c5c" 882 | dependencies = [ 883 | "indexmap", 884 | "serde", 885 | "serde_json", 886 | ] 887 | 888 | [[package]] 889 | name = "parking_lot" 890 | version = "0.12.3" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 893 | dependencies = [ 894 | "lock_api", 895 | "parking_lot_core", 896 | ] 897 | 898 | [[package]] 899 | name = "parking_lot_core" 900 | version = "0.9.10" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 903 | dependencies = [ 904 | "cfg-if", 905 | "libc", 906 | "redox_syscall", 907 | "smallvec", 908 | "windows-targets", 909 | ] 910 | 911 | [[package]] 912 | name = "paste" 913 | version = "1.0.15" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 916 | 917 | [[package]] 918 | name = "percent-encoding" 919 | version = "2.3.1" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 922 | 923 | [[package]] 924 | name = "pin-project-lite" 925 | version = "0.2.16" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 928 | 929 | [[package]] 930 | name = "pin-utils" 931 | version = "0.1.0" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 934 | 935 | [[package]] 936 | name = "powerfmt" 937 | version = "0.2.0" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 940 | 941 | [[package]] 942 | name = "ppv-lite86" 943 | version = "0.2.20" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 946 | dependencies = [ 947 | "zerocopy", 948 | ] 949 | 950 | [[package]] 951 | name = "prettyplease" 952 | version = "0.2.29" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" 955 | dependencies = [ 956 | "proc-macro2", 957 | "syn", 958 | ] 959 | 960 | [[package]] 961 | name = "proc-macro2" 962 | version = "1.0.93" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 965 | dependencies = [ 966 | "unicode-ident", 967 | ] 968 | 969 | [[package]] 970 | name = "proptest" 971 | version = "1.6.0" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" 974 | dependencies = [ 975 | "bitflags", 976 | "lazy_static", 977 | "num-traits", 978 | "rand", 979 | "rand_chacha", 980 | "rand_xorshift", 981 | "regex-syntax", 982 | "unarray", 983 | ] 984 | 985 | [[package]] 986 | name = "quote" 987 | version = "1.0.38" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 990 | dependencies = [ 991 | "proc-macro2", 992 | ] 993 | 994 | [[package]] 995 | name = "rand" 996 | version = "0.8.5" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 999 | dependencies = [ 1000 | "libc", 1001 | "rand_chacha", 1002 | "rand_core", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "rand_chacha" 1007 | version = "0.3.1" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1010 | dependencies = [ 1011 | "ppv-lite86", 1012 | "rand_core", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "rand_core" 1017 | version = "0.6.4" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1020 | dependencies = [ 1021 | "getrandom", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "rand_xorshift" 1026 | version = "0.3.0" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" 1029 | dependencies = [ 1030 | "rand_core", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "redox_syscall" 1035 | version = "0.5.8" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 1038 | dependencies = [ 1039 | "bitflags", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "redox_users" 1044 | version = "0.4.6" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 1047 | dependencies = [ 1048 | "getrandom", 1049 | "libredox", 1050 | "thiserror", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "regex-syntax" 1055 | version = "0.8.5" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1058 | 1059 | [[package]] 1060 | name = "regress" 1061 | version = "0.7.1" 1062 | source = "registry+https://github.com/rust-lang/crates.io-index" 1063 | checksum = "4ed9969cad8051328011596bf549629f1b800cf1731e7964b1eef8dfc480d2c2" 1064 | dependencies = [ 1065 | "hashbrown 0.13.2", 1066 | "memchr", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "ring" 1071 | version = "0.17.14" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1074 | dependencies = [ 1075 | "cc", 1076 | "cfg-if", 1077 | "getrandom", 1078 | "libc", 1079 | "untrusted", 1080 | "windows-sys 0.52.0", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "rustc-demangle" 1085 | version = "0.1.24" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1088 | 1089 | [[package]] 1090 | name = "rustls" 1091 | version = "0.22.4" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" 1094 | dependencies = [ 1095 | "log", 1096 | "ring", 1097 | "rustls-pki-types", 1098 | "rustls-webpki", 1099 | "subtle", 1100 | "zeroize", 1101 | ] 1102 | 1103 | [[package]] 1104 | name = "rustls-pemfile" 1105 | version = "2.2.0" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1108 | dependencies = [ 1109 | "rustls-pki-types", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "rustls-pki-types" 1114 | version = "1.10.1" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" 1117 | 1118 | [[package]] 1119 | name = "rustls-webpki" 1120 | version = "0.102.8" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1123 | dependencies = [ 1124 | "ring", 1125 | "rustls-pki-types", 1126 | "untrusted", 1127 | ] 1128 | 1129 | [[package]] 1130 | name = "rustversion" 1131 | version = "1.0.19" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 1134 | 1135 | [[package]] 1136 | name = "ryu" 1137 | version = "1.0.18" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1140 | 1141 | [[package]] 1142 | name = "schemars" 1143 | version = "0.8.21" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" 1146 | dependencies = [ 1147 | "dyn-clone", 1148 | "schemars_derive", 1149 | "serde", 1150 | "serde_json", 1151 | "uuid", 1152 | ] 1153 | 1154 | [[package]] 1155 | name = "schemars_derive" 1156 | version = "0.8.21" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" 1159 | dependencies = [ 1160 | "proc-macro2", 1161 | "quote", 1162 | "serde_derive_internals", 1163 | "syn", 1164 | ] 1165 | 1166 | [[package]] 1167 | name = "scopeguard" 1168 | version = "1.2.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1171 | 1172 | [[package]] 1173 | name = "serde" 1174 | version = "1.0.217" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1177 | dependencies = [ 1178 | "serde_derive", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "serde_derive" 1183 | version = "1.0.217" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1186 | dependencies = [ 1187 | "proc-macro2", 1188 | "quote", 1189 | "syn", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "serde_derive_internals" 1194 | version = "0.29.1" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" 1197 | dependencies = [ 1198 | "proc-macro2", 1199 | "quote", 1200 | "syn", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "serde_json" 1205 | version = "1.0.135" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" 1208 | dependencies = [ 1209 | "itoa", 1210 | "memchr", 1211 | "ryu", 1212 | "serde", 1213 | ] 1214 | 1215 | [[package]] 1216 | name = "serde_path_to_error" 1217 | version = "0.1.16" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" 1220 | dependencies = [ 1221 | "itoa", 1222 | "serde", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "serde_spanned" 1227 | version = "0.6.8" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1230 | dependencies = [ 1231 | "serde", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "serde_tokenstream" 1236 | version = "0.2.1" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "8790a7c3fe883e443eaa2af6f705952bc5d6e8671a220b9335c8cae92c037e74" 1239 | dependencies = [ 1240 | "proc-macro2", 1241 | "quote", 1242 | "serde", 1243 | "syn", 1244 | ] 1245 | 1246 | [[package]] 1247 | name = "serde_urlencoded" 1248 | version = "0.7.1" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1251 | dependencies = [ 1252 | "form_urlencoded", 1253 | "itoa", 1254 | "ryu", 1255 | "serde", 1256 | ] 1257 | 1258 | [[package]] 1259 | name = "sha1" 1260 | version = "0.10.6" 1261 | source = "registry+https://github.com/rust-lang/crates.io-index" 1262 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1263 | dependencies = [ 1264 | "cfg-if", 1265 | "cpufeatures", 1266 | "digest", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "shlex" 1271 | version = "1.3.0" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1274 | 1275 | [[package]] 1276 | name = "signal-hook-registry" 1277 | version = "1.4.2" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1280 | dependencies = [ 1281 | "libc", 1282 | ] 1283 | 1284 | [[package]] 1285 | name = "similar" 1286 | version = "2.6.0" 1287 | source = "registry+https://github.com/rust-lang/crates.io-index" 1288 | checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" 1289 | 1290 | [[package]] 1291 | name = "slab" 1292 | version = "0.4.9" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1295 | dependencies = [ 1296 | "autocfg", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "slog" 1301 | version = "2.7.0" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" 1304 | 1305 | [[package]] 1306 | name = "slog-async" 1307 | version = "2.8.0" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" 1310 | dependencies = [ 1311 | "crossbeam-channel", 1312 | "slog", 1313 | "take_mut", 1314 | "thread_local", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "slog-bunyan" 1319 | version = "2.5.0" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "dcaaf6e68789d3f0411f1e72bc443214ef252a1038b6e344836e50442541f190" 1322 | dependencies = [ 1323 | "hostname 0.3.1", 1324 | "slog", 1325 | "slog-json", 1326 | "time", 1327 | ] 1328 | 1329 | [[package]] 1330 | name = "slog-json" 1331 | version = "2.6.1" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "3e1e53f61af1e3c8b852eef0a9dee29008f55d6dd63794f3f12cef786cf0f219" 1334 | dependencies = [ 1335 | "serde", 1336 | "serde_json", 1337 | "slog", 1338 | "time", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "slog-term" 1343 | version = "2.9.1" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" 1346 | dependencies = [ 1347 | "is-terminal", 1348 | "slog", 1349 | "term", 1350 | "thread_local", 1351 | "time", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "smallvec" 1356 | version = "1.13.2" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1359 | 1360 | [[package]] 1361 | name = "socket2" 1362 | version = "0.5.8" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1365 | dependencies = [ 1366 | "libc", 1367 | "windows-sys 0.52.0", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "spin" 1372 | version = "0.9.8" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1375 | 1376 | [[package]] 1377 | name = "structmeta" 1378 | version = "0.3.0" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" 1381 | dependencies = [ 1382 | "proc-macro2", 1383 | "quote", 1384 | "structmeta-derive", 1385 | "syn", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "structmeta-derive" 1390 | version = "0.3.0" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" 1393 | dependencies = [ 1394 | "proc-macro2", 1395 | "quote", 1396 | "syn", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "subtle" 1401 | version = "2.6.1" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1404 | 1405 | [[package]] 1406 | name = "syn" 1407 | version = "2.0.96" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 1410 | dependencies = [ 1411 | "proc-macro2", 1412 | "quote", 1413 | "unicode-ident", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "take_mut" 1418 | version = "0.2.2" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" 1421 | 1422 | [[package]] 1423 | name = "term" 1424 | version = "0.7.0" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" 1427 | dependencies = [ 1428 | "dirs-next", 1429 | "rustversion", 1430 | "winapi", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "test-strategy" 1435 | version = "0.4.0" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "2bf41af45e3f54cc184831d629d41d5b2bda8297e29c81add7ae4f362ed5e01b" 1438 | dependencies = [ 1439 | "proc-macro2", 1440 | "quote", 1441 | "structmeta", 1442 | "syn", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "thiserror" 1447 | version = "1.0.69" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1450 | dependencies = [ 1451 | "thiserror-impl", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "thiserror-impl" 1456 | version = "1.0.69" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1459 | dependencies = [ 1460 | "proc-macro2", 1461 | "quote", 1462 | "syn", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "thread_local" 1467 | version = "1.1.8" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1470 | dependencies = [ 1471 | "cfg-if", 1472 | "once_cell", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "time" 1477 | version = "0.3.36" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 1480 | dependencies = [ 1481 | "deranged", 1482 | "itoa", 1483 | "libc", 1484 | "num-conv", 1485 | "num_threads", 1486 | "powerfmt", 1487 | "serde", 1488 | "time-core", 1489 | "time-macros", 1490 | ] 1491 | 1492 | [[package]] 1493 | name = "time-core" 1494 | version = "0.1.2" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1497 | 1498 | [[package]] 1499 | name = "time-macros" 1500 | version = "0.2.18" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" 1503 | dependencies = [ 1504 | "num-conv", 1505 | "time-core", 1506 | ] 1507 | 1508 | [[package]] 1509 | name = "tokio" 1510 | version = "1.44.2" 1511 | source = "registry+https://github.com/rust-lang/crates.io-index" 1512 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 1513 | dependencies = [ 1514 | "backtrace", 1515 | "bytes", 1516 | "libc", 1517 | "mio", 1518 | "parking_lot", 1519 | "pin-project-lite", 1520 | "signal-hook-registry", 1521 | "socket2", 1522 | "tokio-macros", 1523 | "windows-sys 0.52.0", 1524 | ] 1525 | 1526 | [[package]] 1527 | name = "tokio-macros" 1528 | version = "2.5.0" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1531 | dependencies = [ 1532 | "proc-macro2", 1533 | "quote", 1534 | "syn", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "tokio-rustls" 1539 | version = "0.25.0" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" 1542 | dependencies = [ 1543 | "rustls", 1544 | "rustls-pki-types", 1545 | "tokio", 1546 | ] 1547 | 1548 | [[package]] 1549 | name = "tokio-util" 1550 | version = "0.7.11" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 1553 | dependencies = [ 1554 | "bytes", 1555 | "futures-core", 1556 | "futures-sink", 1557 | "pin-project-lite", 1558 | "tokio", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "toml" 1563 | version = "0.8.19" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 1566 | dependencies = [ 1567 | "serde", 1568 | "serde_spanned", 1569 | "toml_datetime", 1570 | "toml_edit", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "toml_datetime" 1575 | version = "0.6.8" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1578 | dependencies = [ 1579 | "serde", 1580 | ] 1581 | 1582 | [[package]] 1583 | name = "toml_edit" 1584 | version = "0.22.22" 1585 | source = "registry+https://github.com/rust-lang/crates.io-index" 1586 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 1587 | dependencies = [ 1588 | "indexmap", 1589 | "serde", 1590 | "serde_spanned", 1591 | "toml_datetime", 1592 | "winnow", 1593 | ] 1594 | 1595 | [[package]] 1596 | name = "tower-service" 1597 | version = "0.3.3" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1600 | 1601 | [[package]] 1602 | name = "tracing" 1603 | version = "0.1.41" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1606 | dependencies = [ 1607 | "pin-project-lite", 1608 | "tracing-core", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "tracing-core" 1613 | version = "0.1.33" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1616 | dependencies = [ 1617 | "once_cell", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "try-lock" 1622 | version = "0.2.5" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1625 | 1626 | [[package]] 1627 | name = "typenum" 1628 | version = "1.17.0" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1631 | 1632 | [[package]] 1633 | name = "typify" 1634 | version = "0.0.15" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "63ed4d717aa95e598e2f9183376b060e95669ef8f444701ea6afb990fde1cf69" 1637 | dependencies = [ 1638 | "typify-impl", 1639 | "typify-macro", 1640 | ] 1641 | 1642 | [[package]] 1643 | name = "typify-impl" 1644 | version = "0.0.15" 1645 | source = "registry+https://github.com/rust-lang/crates.io-index" 1646 | checksum = "89057244dfade7c58af9e62beccbcbeb7a7e7701697a33b06dbe0b7331fb79cf" 1647 | dependencies = [ 1648 | "heck", 1649 | "log", 1650 | "proc-macro2", 1651 | "quote", 1652 | "regress", 1653 | "schemars", 1654 | "serde_json", 1655 | "syn", 1656 | "thiserror", 1657 | "unicode-ident", 1658 | ] 1659 | 1660 | [[package]] 1661 | name = "typify-macro" 1662 | version = "0.0.15" 1663 | source = "registry+https://github.com/rust-lang/crates.io-index" 1664 | checksum = "2ddade397f5957d2cd7fb27f905a9a569db20e8e1e3ea589edce40be07b92825" 1665 | dependencies = [ 1666 | "proc-macro2", 1667 | "quote", 1668 | "schemars", 1669 | "serde", 1670 | "serde_json", 1671 | "serde_tokenstream", 1672 | "syn", 1673 | "typify-impl", 1674 | ] 1675 | 1676 | [[package]] 1677 | name = "unarray" 1678 | version = "0.1.4" 1679 | source = "registry+https://github.com/rust-lang/crates.io-index" 1680 | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" 1681 | 1682 | [[package]] 1683 | name = "unicode-ident" 1684 | version = "1.0.14" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1687 | 1688 | [[package]] 1689 | name = "unicode-segmentation" 1690 | version = "1.12.0" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 1693 | 1694 | [[package]] 1695 | name = "unicode-width" 1696 | version = "0.2.0" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 1699 | 1700 | [[package]] 1701 | name = "untrusted" 1702 | version = "0.9.0" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1705 | 1706 | [[package]] 1707 | name = "uuid" 1708 | version = "1.12.0" 1709 | source = "registry+https://github.com/rust-lang/crates.io-index" 1710 | checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" 1711 | dependencies = [ 1712 | "getrandom", 1713 | "serde", 1714 | ] 1715 | 1716 | [[package]] 1717 | name = "version_check" 1718 | version = "0.9.5" 1719 | source = "registry+https://github.com/rust-lang/crates.io-index" 1720 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1721 | 1722 | [[package]] 1723 | name = "waitgroup" 1724 | version = "0.1.2" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" 1727 | dependencies = [ 1728 | "atomic-waker", 1729 | ] 1730 | 1731 | [[package]] 1732 | name = "want" 1733 | version = "0.3.1" 1734 | source = "registry+https://github.com/rust-lang/crates.io-index" 1735 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1736 | dependencies = [ 1737 | "try-lock", 1738 | ] 1739 | 1740 | [[package]] 1741 | name = "wasi" 1742 | version = "0.11.0+wasi-snapshot-preview1" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1745 | 1746 | [[package]] 1747 | name = "wasm-bindgen" 1748 | version = "0.2.100" 1749 | source = "registry+https://github.com/rust-lang/crates.io-index" 1750 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 1751 | dependencies = [ 1752 | "cfg-if", 1753 | "once_cell", 1754 | "rustversion", 1755 | "wasm-bindgen-macro", 1756 | ] 1757 | 1758 | [[package]] 1759 | name = "wasm-bindgen-backend" 1760 | version = "0.2.100" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 1763 | dependencies = [ 1764 | "bumpalo", 1765 | "log", 1766 | "proc-macro2", 1767 | "quote", 1768 | "syn", 1769 | "wasm-bindgen-shared", 1770 | ] 1771 | 1772 | [[package]] 1773 | name = "wasm-bindgen-macro" 1774 | version = "0.2.100" 1775 | source = "registry+https://github.com/rust-lang/crates.io-index" 1776 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 1777 | dependencies = [ 1778 | "quote", 1779 | "wasm-bindgen-macro-support", 1780 | ] 1781 | 1782 | [[package]] 1783 | name = "wasm-bindgen-macro-support" 1784 | version = "0.2.100" 1785 | source = "registry+https://github.com/rust-lang/crates.io-index" 1786 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 1787 | dependencies = [ 1788 | "proc-macro2", 1789 | "quote", 1790 | "syn", 1791 | "wasm-bindgen-backend", 1792 | "wasm-bindgen-shared", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "wasm-bindgen-shared" 1797 | version = "0.2.100" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 1800 | dependencies = [ 1801 | "unicode-ident", 1802 | ] 1803 | 1804 | [[package]] 1805 | name = "winapi" 1806 | version = "0.3.9" 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" 1808 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1809 | dependencies = [ 1810 | "winapi-i686-pc-windows-gnu", 1811 | "winapi-x86_64-pc-windows-gnu", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "winapi-i686-pc-windows-gnu" 1816 | version = "0.4.0" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1819 | 1820 | [[package]] 1821 | name = "winapi-x86_64-pc-windows-gnu" 1822 | version = "0.4.0" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1825 | 1826 | [[package]] 1827 | name = "windows" 1828 | version = "0.52.0" 1829 | source = "registry+https://github.com/rust-lang/crates.io-index" 1830 | checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" 1831 | dependencies = [ 1832 | "windows-core", 1833 | "windows-targets", 1834 | ] 1835 | 1836 | [[package]] 1837 | name = "windows-core" 1838 | version = "0.52.0" 1839 | source = "registry+https://github.com/rust-lang/crates.io-index" 1840 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1841 | dependencies = [ 1842 | "windows-targets", 1843 | ] 1844 | 1845 | [[package]] 1846 | name = "windows-sys" 1847 | version = "0.52.0" 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" 1849 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1850 | dependencies = [ 1851 | "windows-targets", 1852 | ] 1853 | 1854 | [[package]] 1855 | name = "windows-sys" 1856 | version = "0.59.0" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1859 | dependencies = [ 1860 | "windows-targets", 1861 | ] 1862 | 1863 | [[package]] 1864 | name = "windows-targets" 1865 | version = "0.52.6" 1866 | source = "registry+https://github.com/rust-lang/crates.io-index" 1867 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1868 | dependencies = [ 1869 | "windows_aarch64_gnullvm", 1870 | "windows_aarch64_msvc", 1871 | "windows_i686_gnu", 1872 | "windows_i686_gnullvm", 1873 | "windows_i686_msvc", 1874 | "windows_x86_64_gnu", 1875 | "windows_x86_64_gnullvm", 1876 | "windows_x86_64_msvc", 1877 | ] 1878 | 1879 | [[package]] 1880 | name = "windows_aarch64_gnullvm" 1881 | version = "0.52.6" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1884 | 1885 | [[package]] 1886 | name = "windows_aarch64_msvc" 1887 | version = "0.52.6" 1888 | source = "registry+https://github.com/rust-lang/crates.io-index" 1889 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1890 | 1891 | [[package]] 1892 | name = "windows_i686_gnu" 1893 | version = "0.52.6" 1894 | source = "registry+https://github.com/rust-lang/crates.io-index" 1895 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1896 | 1897 | [[package]] 1898 | name = "windows_i686_gnullvm" 1899 | version = "0.52.6" 1900 | source = "registry+https://github.com/rust-lang/crates.io-index" 1901 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1902 | 1903 | [[package]] 1904 | name = "windows_i686_msvc" 1905 | version = "0.52.6" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1908 | 1909 | [[package]] 1910 | name = "windows_x86_64_gnu" 1911 | version = "0.52.6" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1914 | 1915 | [[package]] 1916 | name = "windows_x86_64_gnullvm" 1917 | version = "0.52.6" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1920 | 1921 | [[package]] 1922 | name = "windows_x86_64_msvc" 1923 | version = "0.52.6" 1924 | source = "registry+https://github.com/rust-lang/crates.io-index" 1925 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1926 | 1927 | [[package]] 1928 | name = "winnow" 1929 | version = "0.6.24" 1930 | source = "registry+https://github.com/rust-lang/crates.io-index" 1931 | checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" 1932 | dependencies = [ 1933 | "memchr", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "zerocopy" 1938 | version = "0.7.35" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1941 | dependencies = [ 1942 | "byteorder", 1943 | "zerocopy-derive", 1944 | ] 1945 | 1946 | [[package]] 1947 | name = "zerocopy-derive" 1948 | version = "0.7.35" 1949 | source = "registry+https://github.com/rust-lang/crates.io-index" 1950 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1951 | dependencies = [ 1952 | "proc-macro2", 1953 | "quote", 1954 | "syn", 1955 | ] 1956 | 1957 | [[package]] 1958 | name = "zeroize" 1959 | version = "1.8.1" 1960 | source = "registry+https://github.com/rust-lang/crates.io-index" 1961 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1962 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "crates/*", 5 | ] 6 | 7 | [workspace.package] 8 | rust-version = "1.67" 9 | 10 | [workspace.dependencies] 11 | dropshot = "0.10.0" 12 | expectorate = "1.0.6" 13 | newtype-uuid = { path = "crates/newtype-uuid" } 14 | prettyplease = "0.2.22" 15 | # Ideally we'd let you use no-std proptest, but proptest requires either the std 16 | # or the no_std option to be set. It won't compile without one of those two set. 17 | proptest = { version = "1.5.0", features = ["std"], default-features = false } 18 | schemars = "0.8.17" 19 | serde = "1" 20 | serde_json = "1.0.115" 21 | syn = "2.0.48" 22 | test-strategy = "0.4.0" 23 | typify = "0.0.15" 24 | uuid = { version = "1.7.0", default-features = false } 25 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright (c) 2016 Alex Crichton 190 | Copyright (c) 2017 The Tokio Authors 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Oxide Computer Company 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | crates/newtype-uuid/README.md -------------------------------------------------------------------------------- /crates/integration-tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "integration-tests" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT OR Apache-2.0" 6 | publish = false 7 | 8 | [dependencies] 9 | newtype-uuid.workspace = true 10 | dropshot = { workspace = true, optional = true } 11 | expectorate = { workspace = true, optional = true } 12 | prettyplease = { workspace = true, optional = true } 13 | proptest = { workspace = true, optional = true } 14 | schemars = { workspace = true, optional = true } 15 | serde = { workspace = true, optional = true } 16 | serde_json = { workspace = true, optional = true } 17 | syn = { workspace = true, optional = true } 18 | test-strategy = { workspace = true, optional = true } 19 | typify = { workspace = true, optional = true } 20 | uuid.workspace = true 21 | 22 | [features] 23 | internal-schemars08-tests = [ 24 | "newtype-uuid/schemars08", 25 | "newtype-uuid/serde", 26 | "dep:dropshot", 27 | "dep:expectorate", 28 | "dep:prettyplease", 29 | "dep:schemars", 30 | "dep:serde_json", 31 | "dep:serde", 32 | "dep:syn", 33 | "dep:typify", 34 | ] 35 | internal-proptest1-tests = [ 36 | "newtype-uuid/proptest1", 37 | "dep:proptest", 38 | "dep:test-strategy", 39 | ] 40 | -------------------------------------------------------------------------------- /crates/integration-tests/outputs/schema-rust-with-replace.rs: -------------------------------------------------------------------------------- 1 | ///MyPathStruct 2 | /// 3 | ///
JSON schema 4 | /// 5 | /// ```json 6 | /**{ 7 | "title": "MyPathStruct", 8 | "type": "object", 9 | "required": [ 10 | "id" 11 | ], 12 | "properties": { 13 | "id": { 14 | "$ref": "#/definitions/TypedUuidForMyKind" 15 | } 16 | } 17 | }*/ 18 | /// ``` 19 | ///
20 | #[derive(Clone, Debug, Deserialize, Serialize)] 21 | pub struct MyPathStruct { 22 | pub id: ::newtype_uuid::TypedUuid<::my_crate::MyKind>, 23 | } 24 | impl From<&MyPathStruct> for MyPathStruct { 25 | fn from(value: &MyPathStruct) -> Self { 26 | value.clone() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /crates/integration-tests/outputs/schema-rust.rs: -------------------------------------------------------------------------------- 1 | ///MyPathStruct 2 | /// 3 | ///
JSON schema 4 | /// 5 | /// ```json 6 | /**{ 7 | "title": "MyPathStruct", 8 | "type": "object", 9 | "required": [ 10 | "id" 11 | ], 12 | "properties": { 13 | "id": { 14 | "$ref": "#/definitions/TypedUuidForMyKind" 15 | } 16 | } 17 | }*/ 18 | /// ``` 19 | ///
20 | #[derive(Clone, Debug, Deserialize, Serialize)] 21 | pub struct MyPathStruct { 22 | pub id: TypedUuidForMyKind, 23 | } 24 | impl From<&MyPathStruct> for MyPathStruct { 25 | fn from(value: &MyPathStruct) -> Self { 26 | value.clone() 27 | } 28 | } 29 | ///TypedUuidForMyKind 30 | /// 31 | ///
JSON schema 32 | /// 33 | /// ```json 34 | /**{ 35 | "type": "string", 36 | "format": "uuid" 37 | }*/ 38 | /// ``` 39 | ///
40 | #[derive(Clone, Debug, Deserialize, Serialize)] 41 | pub struct TypedUuidForMyKind(pub uuid::Uuid); 42 | impl std::ops::Deref for TypedUuidForMyKind { 43 | type Target = uuid::Uuid; 44 | fn deref(&self) -> &uuid::Uuid { 45 | &self.0 46 | } 47 | } 48 | impl From for uuid::Uuid { 49 | fn from(value: TypedUuidForMyKind) -> Self { 50 | value.0 51 | } 52 | } 53 | impl From<&TypedUuidForMyKind> for TypedUuidForMyKind { 54 | fn from(value: &TypedUuidForMyKind) -> Self { 55 | value.clone() 56 | } 57 | } 58 | impl From for TypedUuidForMyKind { 59 | fn from(value: uuid::Uuid) -> Self { 60 | Self(value) 61 | } 62 | } 63 | impl std::str::FromStr for TypedUuidForMyKind { 64 | type Err = ::Err; 65 | fn from_str(value: &str) -> Result { 66 | Ok(Self(value.parse()?)) 67 | } 68 | } 69 | impl std::convert::TryFrom<&str> for TypedUuidForMyKind { 70 | type Error = ::Err; 71 | fn try_from(value: &str) -> Result { 72 | value.parse() 73 | } 74 | } 75 | impl std::convert::TryFrom<&String> for TypedUuidForMyKind { 76 | type Error = ::Err; 77 | fn try_from(value: &String) -> Result { 78 | value.parse() 79 | } 80 | } 81 | impl std::convert::TryFrom for TypedUuidForMyKind { 82 | type Error = ::Err; 83 | fn try_from(value: String) -> Result { 84 | value.parse() 85 | } 86 | } 87 | impl ToString for TypedUuidForMyKind { 88 | fn to_string(&self) -> String { 89 | self.0.to_string() 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /crates/integration-tests/outputs/typed-uuid-openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "responses": { 4 | "Error": { 5 | "content": { 6 | "application/json": { 7 | "schema": { 8 | "$ref": "#/components/schemas/Error" 9 | } 10 | } 11 | }, 12 | "description": "Error" 13 | } 14 | }, 15 | "schemas": { 16 | "Error": { 17 | "description": "Error information from a response.", 18 | "properties": { 19 | "error_code": { 20 | "type": "string" 21 | }, 22 | "message": { 23 | "type": "string" 24 | }, 25 | "request_id": { 26 | "type": "string" 27 | } 28 | }, 29 | "required": [ 30 | "message", 31 | "request_id" 32 | ], 33 | "type": "object" 34 | }, 35 | "MyPathStruct": { 36 | "properties": { 37 | "id": { 38 | "$ref": "#/components/schemas/TypedUuidForMyKind" 39 | } 40 | }, 41 | "required": [ 42 | "id" 43 | ], 44 | "type": "object" 45 | }, 46 | "TypedUuidForMyKind": { 47 | "format": "uuid", 48 | "type": "string" 49 | } 50 | } 51 | }, 52 | "info": { 53 | "title": "my-api", 54 | "version": "1.0.0" 55 | }, 56 | "openapi": "3.0.3", 57 | "paths": { 58 | "/my-endpoint/{id}": { 59 | "post": { 60 | "operationId": "my_endpoint", 61 | "parameters": [ 62 | { 63 | "in": "path", 64 | "name": "id", 65 | "required": true, 66 | "schema": { 67 | "$ref": "#/components/schemas/TypedUuidForMyKind" 68 | } 69 | }, 70 | { 71 | "in": "query", 72 | "name": "query_id", 73 | "required": true, 74 | "schema": { 75 | "$ref": "#/components/schemas/TypedUuidForMyKind" 76 | } 77 | } 78 | ], 79 | "requestBody": { 80 | "content": { 81 | "application/json": { 82 | "schema": { 83 | "$ref": "#/components/schemas/MyPathStruct" 84 | } 85 | } 86 | }, 87 | "required": true 88 | }, 89 | "responses": { 90 | "200": { 91 | "content": { 92 | "application/json": { 93 | "schema": { 94 | "$ref": "#/components/schemas/MyPathStruct" 95 | } 96 | } 97 | }, 98 | "description": "successful operation" 99 | }, 100 | "4XX": { 101 | "$ref": "#/components/responses/Error" 102 | }, 103 | "5XX": { 104 | "$ref": "#/components/responses/Error" 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /crates/integration-tests/outputs/typed-uuid-rust.rs: -------------------------------------------------------------------------------- 1 | ///MyPathStruct 2 | /// 3 | ///
JSON schema 4 | /// 5 | /// ```json 6 | /**{ 7 | "title": "MyPathStruct", 8 | "type": "object", 9 | "required": [ 10 | "id" 11 | ], 12 | "properties": { 13 | "id": { 14 | "$ref": "#/definitions/TypedUuidForMyKind" 15 | } 16 | } 17 | }*/ 18 | /// ``` 19 | ///
20 | #[derive(Clone, Debug, Deserialize, Serialize)] 21 | pub struct MyPathStruct { 22 | pub id: TypedUuidForMyKind, 23 | } 24 | impl From<&MyPathStruct> for MyPathStruct { 25 | fn from(value: &MyPathStruct) -> Self { 26 | value.clone() 27 | } 28 | } 29 | ///TypedUuidForMyKind 30 | /// 31 | ///
JSON schema 32 | /// 33 | /// ```json 34 | /**{ 35 | "type": "string", 36 | "format": "uuid" 37 | }*/ 38 | /// ``` 39 | ///
40 | #[derive(Clone, Debug, Deserialize, Serialize)] 41 | pub struct TypedUuidForMyKind(pub uuid::Uuid); 42 | impl std::ops::Deref for TypedUuidForMyKind { 43 | type Target = uuid::Uuid; 44 | fn deref(&self) -> &uuid::Uuid { 45 | &self.0 46 | } 47 | } 48 | impl From for uuid::Uuid { 49 | fn from(value: TypedUuidForMyKind) -> Self { 50 | value.0 51 | } 52 | } 53 | impl From<&TypedUuidForMyKind> for TypedUuidForMyKind { 54 | fn from(value: &TypedUuidForMyKind) -> Self { 55 | value.clone() 56 | } 57 | } 58 | impl From for TypedUuidForMyKind { 59 | fn from(value: uuid::Uuid) -> Self { 60 | Self(value) 61 | } 62 | } 63 | impl std::str::FromStr for TypedUuidForMyKind { 64 | type Err = ::Err; 65 | fn from_str(value: &str) -> Result { 66 | Ok(Self(value.parse()?)) 67 | } 68 | } 69 | impl std::convert::TryFrom<&str> for TypedUuidForMyKind { 70 | type Error = ::Err; 71 | fn try_from(value: &str) -> Result { 72 | value.parse() 73 | } 74 | } 75 | impl std::convert::TryFrom<&String> for TypedUuidForMyKind { 76 | type Error = ::Err; 77 | fn try_from(value: &String) -> Result { 78 | value.parse() 79 | } 80 | } 81 | impl std::convert::TryFrom for TypedUuidForMyKind { 82 | type Error = ::Err; 83 | fn try_from(value: String) -> Result { 84 | value.parse() 85 | } 86 | } 87 | impl ToString for TypedUuidForMyKind { 88 | fn to_string(&self) -> String { 89 | self.0.to_string() 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /crates/integration-tests/outputs/typed-uuid-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "title": "MyPathStruct", 4 | "type": "object", 5 | "required": [ 6 | "id" 7 | ], 8 | "properties": { 9 | "id": { 10 | "$ref": "#/definitions/TypedUuidForMyKind" 11 | } 12 | }, 13 | "definitions": { 14 | "TypedUuidForMyKind": { 15 | "type": "string", 16 | "format": "uuid" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /crates/integration-tests/src/json_schema.rs: -------------------------------------------------------------------------------- 1 | //! JSON schema tests for newtype-uuid. 2 | 3 | use dropshot::{ 4 | endpoint, ApiDescription, HttpError, HttpResponseOk, Path, Query, RequestContext, TypedBody, 5 | }; 6 | use newtype_uuid::{TypedUuid, TypedUuidKind, TypedUuidTag}; 7 | use schemars::JsonSchema; 8 | use serde::{Deserialize, Serialize}; 9 | use typify::TypeSpaceSettings; 10 | 11 | #[derive(Debug, JsonSchema)] 12 | enum MyKind {} 13 | 14 | impl TypedUuidKind for MyKind { 15 | fn tag() -> TypedUuidTag { 16 | const TAG: TypedUuidTag = TypedUuidTag::new("my_kind"); 17 | TAG 18 | } 19 | } 20 | 21 | #[derive(Deserialize, Serialize, JsonSchema)] 22 | struct MyPathStruct { 23 | id: TypedUuid, 24 | } 25 | 26 | #[derive(Deserialize, Serialize, JsonSchema)] 27 | struct MyQueryStruct { 28 | query_id: TypedUuid, 29 | } 30 | 31 | #[endpoint { 32 | method = POST, 33 | path = "/my-endpoint/{id}", 34 | }] 35 | async fn my_endpoint( 36 | _rqctx: RequestContext<()>, 37 | _path: Path, 38 | _query: Query, 39 | _body: TypedBody, 40 | ) -> Result, HttpError> { 41 | unreachable!("this method is never actually called") 42 | } 43 | 44 | #[test] 45 | fn test_json_schema_snapshot() { 46 | let schema = schemars::schema_for!(MyPathStruct); 47 | let schema_json = serde_json::to_string_pretty(&schema).unwrap(); 48 | println!("{}", std::env::current_dir().unwrap().display()); 49 | expectorate::assert_contents("outputs/typed-uuid-schema.json", &schema_json); 50 | 51 | // Now attempt to use typify to convert the JSON schema into Rust code. 52 | let output = generate_schema_with(&TypeSpaceSettings::default(), schema.clone()); 53 | expectorate::assert_contents("outputs/schema-rust.rs", &output); 54 | 55 | // Do so, with a replace directive. 56 | let mut settings = TypeSpaceSettings::default(); 57 | settings.with_replacement( 58 | "TypedUuidForMyKind", 59 | "::newtype_uuid::TypedUuid<::my_crate::MyKind>", 60 | std::iter::empty(), 61 | ); 62 | let output = generate_schema_with(&settings, schema); 63 | expectorate::assert_contents("outputs/schema-rust-with-replace.rs", &output); 64 | } 65 | 66 | fn generate_schema_with( 67 | settings: &TypeSpaceSettings, 68 | schema: schemars::schema::RootSchema, 69 | ) -> String { 70 | let mut type_space = typify::TypeSpace::new(settings); 71 | type_space 72 | .add_root_schema(schema) 73 | .expect("adding root schema succeeded"); 74 | let tokens = type_space.to_stream(); 75 | let file: syn::File = syn::parse2(tokens).expect("parsing tokens succeeded"); 76 | prettyplease::unparse(&file) 77 | } 78 | 79 | #[test] 80 | fn test_openapi_snapshot() { 81 | let mut api = ApiDescription::new(); 82 | api.register(my_endpoint).unwrap(); 83 | let openapi = api.openapi("my-api", "1.0.0"); 84 | let json_value = openapi.json().expect("serialization to json worked"); 85 | let api_json = serde_json::to_string_pretty(&json_value).unwrap(); 86 | expectorate::assert_contents("outputs/typed-uuid-openapi.json", &api_json); 87 | } 88 | -------------------------------------------------------------------------------- /crates/integration-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Integration tests. 2 | 3 | #[cfg(all(test, feature = "internal-schemars08-tests"))] 4 | mod json_schema; 5 | #[cfg(all(test, feature = "internal-proptest1-tests"))] 6 | mod proptests; 7 | -------------------------------------------------------------------------------- /crates/integration-tests/src/proptests.rs: -------------------------------------------------------------------------------- 1 | //! Tests for the property-based infrastructure. 2 | 3 | use newtype_uuid::{GenericUuid, TypedUuid, TypedUuidKind, TypedUuidTag}; 4 | use test_strategy::proptest; 5 | use uuid::Version; 6 | 7 | #[derive(Debug)] 8 | enum MyKind {} 9 | 10 | impl TypedUuidKind for MyKind { 11 | fn tag() -> TypedUuidTag { 12 | const TAG: TypedUuidTag = TypedUuidTag::new("my_kind"); 13 | TAG 14 | } 15 | } 16 | 17 | /// Ensure that generated UUIDs are always v4. 18 | #[proptest] 19 | fn prop_is_valid_v4(uuid: TypedUuid) { 20 | assert_eq!(uuid.get_version(), Some(Version::Random)); 21 | } 22 | 23 | /// Ensure that AsRef and conversions to Vec match Uuid. 24 | #[proptest] 25 | fn prop_as_bytes(typed_uuid: TypedUuid) { 26 | let typed_uuid_ref: &[u8] = typed_uuid.as_ref(); 27 | let untyped_uuid_ref: &[u8] = typed_uuid.as_untyped_uuid().as_ref(); 28 | assert_eq!(typed_uuid_ref, untyped_uuid_ref); 29 | 30 | let typed_uuid_vec: Vec = typed_uuid.into(); 31 | let untyped_uuid_vec: Vec = typed_uuid.into_untyped_uuid().into(); 32 | assert_eq!(typed_uuid_vec, untyped_uuid_vec); 33 | } 34 | -------------------------------------------------------------------------------- /crates/newtype-uuid/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ../../CHANGELOG.md -------------------------------------------------------------------------------- /crates/newtype-uuid/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "newtype-uuid" 3 | version = "1.2.2" 4 | edition = "2021" 5 | license = "MIT OR Apache-2.0" 6 | repository = "https://github.com/oxidecomputer/newtype-uuid" 7 | description = "Newtype wrapper around UUIDs" 8 | documentation = "https://docs.rs/newtype-uuid" 9 | readme = "README.md" 10 | keywords = ["uuid", "unique", "guid", "newtype"] 11 | categories = ["data-structures", "no-std"] 12 | rust-version.workspace = true 13 | exclude = [".cargo/**/*", ".github/**/*", "scripts/**/*"] 14 | 15 | [package.metadata.docs.rs] 16 | all-features = true 17 | rustdoc-args = ["--cfg=doc_cfg"] 18 | 19 | [dependencies] 20 | proptest = { workspace = true, optional = true } 21 | serde = { workspace = true, features = ["derive"], optional = true } 22 | schemars = { workspace = true, features = ["uuid1"], optional = true } 23 | uuid.workspace = true 24 | 25 | [features] 26 | default = ["uuid/default", "std"] 27 | std = ["alloc", "uuid/std"] 28 | alloc = [] 29 | v4 = ["uuid/v4"] 30 | serde = ["dep:serde", "uuid/serde"] 31 | schemars08 = ["dep:schemars", "std"] 32 | proptest1 = ["dep:proptest"] 33 | -------------------------------------------------------------------------------- /crates/newtype-uuid/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../../LICENSE-APACHE -------------------------------------------------------------------------------- /crates/newtype-uuid/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../../LICENSE-MIT -------------------------------------------------------------------------------- /crates/newtype-uuid/README.md: -------------------------------------------------------------------------------- 1 | # newtype-uuid 2 | 3 | [![newtype-uuid on crates.io](https://img.shields.io/crates/v/newtype-uuid)](https://crates.io/crates/newtype-uuid) 4 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest%20version-brightgreen.svg)](https://docs.rs/newtype-uuid) 5 | [![Documentation (main)](https://img.shields.io/badge/docs-main-brightgreen)](https://oxidecomputer.github.io/newtype-uuid/rustdoc/newtype_uuid/) 6 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](LICENSE-APACHE) 7 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE-MIT) 8 | 9 | A newtype wrapper around `Uuid`. 10 | 11 | ## Motivation 12 | 13 | Many large systems use UUIDs as unique identifiers for various entities. However, the `Uuid` 14 | type does not carry information about the kind of entity it identifies, which can lead to mixing 15 | up different types of UUIDs at runtime. 16 | 17 | This crate provides a wrapper type around `Uuid` that allows you to specify the kind of entity 18 | the UUID identifies. 19 | 20 | ## Example 21 | 22 | ```rust 23 | use newtype_uuid::{GenericUuid, TypedUuid, TypedUuidKind, TypedUuidTag}; 24 | 25 | // First, define a type that represents the kind of UUID this is. 26 | enum MyKind {} 27 | 28 | impl TypedUuidKind for MyKind { 29 | fn tag() -> TypedUuidTag { 30 | // Tags are required to be ASCII identifiers, with underscores 31 | // and dashes also supported. The validity of a tag can be checked 32 | // at compile time by assigning it to a const, like so: 33 | const TAG: TypedUuidTag = TypedUuidTag::new("my_kind"); 34 | TAG 35 | } 36 | } 37 | 38 | // Now, a UUID can be created with this kind. 39 | let uuid: TypedUuid = "dffc3068-1cd6-47d5-b2f3-636b41b07084".parse().unwrap(); 40 | 41 | // The Display (and therefore ToString) impls still show the same value. 42 | assert_eq!(uuid.to_string(), "dffc3068-1cd6-47d5-b2f3-636b41b07084"); 43 | 44 | // The Debug impl will show the tag as well. 45 | assert_eq!(format!("{:?}", uuid), "dffc3068-1cd6-47d5-b2f3-636b41b07084 (my_kind)"); 46 | ``` 47 | 48 | If you have a large number of UUID kinds, consider defining a macro for your purposes. An 49 | example macro: 50 | 51 | ```rust 52 | macro_rules! impl_typed_uuid_kind { 53 | ($($kind:ident => $tag:literal),* $(,)?) => { 54 | $( 55 | pub enum $kind {} 56 | 57 | impl TypedUuidKind for $kind { 58 | #[inline] 59 | fn tag() -> TypedUuidTag { 60 | const TAG: TypedUuidTag = TypedUuidTag::new($tag); 61 | TAG 62 | } 63 | } 64 | )* 65 | }; 66 | } 67 | 68 | // Invoke this macro with: 69 | impl_typed_uuid_kind! { 70 | Kind1 => "kind1", 71 | Kind2 => "kind2", 72 | } 73 | ``` 74 | 75 | ## Implementations 76 | 77 | In general, `TypedUuid` uses the same wire and serialization formats as `Uuid`. This means 78 | that persistent representations of `TypedUuid` are the same as `Uuid`; `TypedUuid` is 79 | intended to be helpful within Rust code, not across serialization boundaries. 80 | 81 | - The `Display` and `FromStr` impls are forwarded to the underlying `Uuid`. 82 | - If the `serde` feature is enabled, `TypedUuid` will serialize and deserialize using the same 83 | format as `Uuid`. 84 | - If the `schemars08` feature is enabled, `TypedUuid` will implement `JsonSchema` if the 85 | corresponding `TypedUuidKind` implements `JsonSchema`. 86 | 87 | To abstract over typed and untyped UUIDs, the `GenericUuid` trait is provided. This trait also 88 | permits conversions between typed and untyped UUIDs. 89 | 90 | ## Dependencies 91 | 92 | - The only required dependency is the `uuid` crate. Optional features may add further 93 | dependencies. 94 | 95 | ## Features 96 | 97 | - `default`: Enables default features in the newtype-uuid crate. 98 | - `std`: Enables the use of the standard library. *Enabled by default.* 99 | - `serde`: Enables serialization and deserialization support via Serde. *Not enabled by 100 | default.* 101 | - `v4`: Enables the `new_v4` method for generating UUIDs. *Not enabled by default.* 102 | - `schemars08`: Enables support for generating JSON schemas via schemars 0.8. *Not enabled by 103 | default.* Note that the format of the generated schema is **not currently part** of the stable 104 | API, though we hope to stabilize it in the future. 105 | - `proptest1`: Enables support for generating `proptest::Arbitrary` instances of UUIDs. *Not enabled by default.* 106 | 107 | ## Minimum supported Rust version (MSRV) 108 | 109 | The MSRV of this crate is **Rust 1.67.** In general, this crate will follow the MSRV of the 110 | underlying `uuid` crate or of dependencies, with an aim to be conservative. 111 | 112 | Within the 1.x series, MSRV updates will be accompanied by a minor version bump. The MSRVs for 113 | each minor version are: 114 | 115 | * Version **1.0.x**: Rust 1.60. 116 | * Version **1.1.x**: Rust 1.61. This permits `TypedUuid` to have `const fn` methods. 117 | * Version **1.2.x**: Rust 1.67, required by some dependency updates. 118 | 119 | ## Alternatives 120 | 121 | - [`typed-uuid`](https://crates.io/crates/typed-uuid): generally similar, but with a few design 122 | decisions that are different. 123 | 124 | ## License 125 | 126 | This project is available under the terms of either the [Apache 2.0 license](LICENSE-APACHE) or the [MIT 127 | license](LICENSE-MIT). 128 | 129 | 135 | -------------------------------------------------------------------------------- /crates/newtype-uuid/README.tpl: -------------------------------------------------------------------------------- 1 | # {{crate}} 2 | 3 | [![newtype-uuid on crates.io](https://img.shields.io/crates/v/newtype-uuid)](https://crates.io/crates/newtype-uuid) 4 | [![Documentation (latest release)](https://img.shields.io/badge/docs-latest%20version-brightgreen.svg)](https://docs.rs/newtype-uuid) 5 | [![Documentation (main)](https://img.shields.io/badge/docs-main-brightgreen)](https://oxidecomputer.github.io/newtype-uuid/rustdoc/newtype_uuid/) 6 | [![License](https://img.shields.io/badge/license-Apache-green.svg)](LICENSE-APACHE) 7 | [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE-MIT) 8 | 9 | {{readme}} 10 | 11 | ## License 12 | 13 | This project is available under the terms of either the [Apache 2.0 license](LICENSE-APACHE) or the [MIT 14 | license](LICENSE-MIT). 15 | 16 | 22 | -------------------------------------------------------------------------------- /crates/newtype-uuid/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Ideally this would be in the [lints] table in Cargo.toml to avoid a build script, but sadly 3 | // the MSRV for that is Rust 1.75. 4 | // 5 | // TODO: switch to [lints] configuration once the MSRV moves beyond that`. 6 | println!("cargo:rustc-check-cfg=cfg(doc_cfg)"); 7 | } 8 | -------------------------------------------------------------------------------- /crates/newtype-uuid/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A newtype wrapper around [`Uuid`]. 2 | //! 3 | //! # Motivation 4 | //! 5 | //! Many large systems use UUIDs as unique identifiers for various entities. However, the [`Uuid`] 6 | //! type does not carry information about the kind of entity it identifies, which can lead to mixing 7 | //! up different types of UUIDs at runtime. 8 | //! 9 | //! This crate provides a wrapper type around [`Uuid`] that allows you to specify the kind of entity 10 | //! the UUID identifies. 11 | //! 12 | //! # Example 13 | //! 14 | //! ```rust 15 | //! use newtype_uuid::{GenericUuid, TypedUuid, TypedUuidKind, TypedUuidTag}; 16 | //! 17 | //! // First, define a type that represents the kind of UUID this is. 18 | //! enum MyKind {} 19 | //! 20 | //! impl TypedUuidKind for MyKind { 21 | //! fn tag() -> TypedUuidTag { 22 | //! // Tags are required to be ASCII identifiers, with underscores 23 | //! // and dashes also supported. The validity of a tag can be checked 24 | //! // at compile time by assigning it to a const, like so: 25 | //! const TAG: TypedUuidTag = TypedUuidTag::new("my_kind"); 26 | //! TAG 27 | //! } 28 | //! } 29 | //! 30 | //! // Now, a UUID can be created with this kind. 31 | //! let uuid: TypedUuid = "dffc3068-1cd6-47d5-b2f3-636b41b07084".parse().unwrap(); 32 | //! 33 | //! // The Display (and therefore ToString) impls still show the same value. 34 | //! assert_eq!(uuid.to_string(), "dffc3068-1cd6-47d5-b2f3-636b41b07084"); 35 | //! 36 | //! // The Debug impl will show the tag as well. 37 | //! assert_eq!(format!("{:?}", uuid), "dffc3068-1cd6-47d5-b2f3-636b41b07084 (my_kind)"); 38 | //! ``` 39 | //! 40 | //! If you have a large number of UUID kinds, consider defining a macro for your purposes. An 41 | //! example macro: 42 | //! 43 | //! ```rust 44 | //! # use newtype_uuid::{TypedUuidKind, TypedUuidTag}; 45 | //! macro_rules! impl_typed_uuid_kind { 46 | //! ($($kind:ident => $tag:literal),* $(,)?) => { 47 | //! $( 48 | //! pub enum $kind {} 49 | //! 50 | //! impl TypedUuidKind for $kind { 51 | //! #[inline] 52 | //! fn tag() -> TypedUuidTag { 53 | //! const TAG: TypedUuidTag = TypedUuidTag::new($tag); 54 | //! TAG 55 | //! } 56 | //! } 57 | //! )* 58 | //! }; 59 | //! } 60 | //! 61 | //! // Invoke this macro with: 62 | //! impl_typed_uuid_kind! { 63 | //! Kind1 => "kind1", 64 | //! Kind2 => "kind2", 65 | //! } 66 | //! ``` 67 | //! 68 | //! # Implementations 69 | //! 70 | //! In general, [`TypedUuid`] uses the same wire and serialization formats as [`Uuid`]. This means 71 | //! that persistent representations of [`TypedUuid`] are the same as [`Uuid`]; [`TypedUuid`] is 72 | //! intended to be helpful within Rust code, not across serialization boundaries. 73 | //! 74 | //! - The `Display` and `FromStr` impls are forwarded to the underlying [`Uuid`]. 75 | //! - If the `serde` feature is enabled, `TypedUuid` will serialize and deserialize using the same 76 | //! format as [`Uuid`]. 77 | //! - If the `schemars08` feature is enabled, [`TypedUuid`] will implement `JsonSchema` if the 78 | //! corresponding [`TypedUuidKind`] implements `JsonSchema`. 79 | //! 80 | //! To abstract over typed and untyped UUIDs, the [`GenericUuid`] trait is provided. This trait also 81 | //! permits conversions between typed and untyped UUIDs. 82 | //! 83 | //! # Dependencies 84 | //! 85 | //! - The only required dependency is the [`uuid`] crate. Optional features may add further 86 | //! dependencies. 87 | //! 88 | //! # Features 89 | //! 90 | //! - `default`: Enables default features in the newtype-uuid crate. 91 | //! - `std`: Enables the use of the standard library. *Enabled by default.* 92 | //! - `serde`: Enables serialization and deserialization support via Serde. *Not enabled by 93 | //! default.* 94 | //! - `v4`: Enables the `new_v4` method for generating UUIDs. *Not enabled by default.* 95 | //! - `schemars08`: Enables support for generating JSON schemas via schemars 0.8. *Not enabled by 96 | //! default.* Note that the format of the generated schema is **not currently part** of the stable 97 | //! API, though we hope to stabilize it in the future. 98 | //! - `proptest1`: Enables support for generating `proptest::Arbitrary` instances of UUIDs. *Not enabled by default.* 99 | //! 100 | //! # Minimum supported Rust version (MSRV) 101 | //! 102 | //! The MSRV of this crate is **Rust 1.67.** In general, this crate will follow the MSRV of the 103 | //! underlying `uuid` crate or of dependencies, with an aim to be conservative. 104 | //! 105 | //! Within the 1.x series, MSRV updates will be accompanied by a minor version bump. The MSRVs for 106 | //! each minor version are: 107 | //! 108 | //! * Version **1.0.x**: Rust 1.60. 109 | //! * Version **1.1.x**: Rust 1.61. This permits `TypedUuid` to have `const fn` methods. 110 | //! * Version **1.2.x**: Rust 1.67, required by some dependency updates. 111 | //! 112 | //! # Alternatives 113 | //! 114 | //! - [`typed-uuid`](https://crates.io/crates/typed-uuid): generally similar, but with a few design 115 | //! decisions that are different. 116 | 117 | #![forbid(unsafe_code)] 118 | #![warn(missing_docs)] 119 | #![cfg_attr(not(feature = "std"), no_std)] 120 | #![cfg_attr(doc_cfg, feature(doc_cfg, doc_auto_cfg))] 121 | 122 | #[cfg(feature = "alloc")] 123 | extern crate alloc; 124 | 125 | use core::{ 126 | cmp::Ordering, 127 | fmt, 128 | hash::{Hash, Hasher}, 129 | marker::PhantomData, 130 | str::FromStr, 131 | }; 132 | use uuid::{Uuid, Version}; 133 | 134 | /// A UUID with type-level information about what it's used for. 135 | /// 136 | /// For more, see [the library documentation](crate). 137 | #[repr(transparent)] 138 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 139 | #[cfg_attr(feature = "serde", serde(transparent, bound = ""))] 140 | pub struct TypedUuid { 141 | uuid: Uuid, 142 | _phantom: PhantomData, 143 | } 144 | 145 | impl TypedUuid { 146 | /// The 'nil UUID' (all zeros). 147 | /// 148 | /// The nil UUID is a special form of UUID that is specified to have all 149 | /// 128 bits set to zero. 150 | /// 151 | /// # References 152 | /// 153 | /// * [Nil UUID in RFC4122](https://tools.ietf.org/html/rfc4122.html#section-4.1.7) 154 | #[inline] 155 | #[must_use] 156 | pub const fn nil() -> Self { 157 | Self { 158 | uuid: Uuid::nil(), 159 | _phantom: PhantomData, 160 | } 161 | } 162 | 163 | /// The 'max UUID' (all ones). 164 | /// 165 | /// The max UUID is a special form of UUID that is specified to have all 166 | /// 128 bits set to one. 167 | /// 168 | /// # References 169 | /// 170 | /// * [Max UUID in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4) 171 | #[inline] 172 | #[must_use] 173 | pub const fn max() -> Self { 174 | Self { 175 | uuid: Uuid::max(), 176 | _phantom: PhantomData, 177 | } 178 | } 179 | 180 | /// Creates a UUID from four field values. 181 | #[inline] 182 | #[must_use] 183 | pub const fn from_fields(d1: u32, d2: u16, d3: u16, d4: [u8; 8]) -> Self { 184 | Self { 185 | uuid: Uuid::from_fields(d1, d2, d3, &d4), 186 | _phantom: PhantomData, 187 | } 188 | } 189 | 190 | /// Creates a UUID from four field values in little-endian order. 191 | /// 192 | /// The bytes in the `d1`, `d2` and `d3` fields will be flipped to convert into big-endian 193 | /// order. This is based on the endianness of the UUID, rather than the target environment so 194 | /// bytes will be flipped on both big and little endian machines. 195 | #[inline] 196 | #[must_use] 197 | pub const fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: [u8; 8]) -> Self { 198 | Self { 199 | uuid: Uuid::from_fields_le(d1, d2, d3, &d4), 200 | _phantom: PhantomData, 201 | } 202 | } 203 | 204 | /// Creates a UUID from a 128bit value. 205 | #[inline] 206 | #[must_use] 207 | pub const fn from_u128(value: u128) -> Self { 208 | Self { 209 | uuid: Uuid::from_u128(value), 210 | _phantom: PhantomData, 211 | } 212 | } 213 | 214 | /// Creates a UUID from a 128bit value in little-endian order. 215 | /// 216 | /// The entire value will be flipped to convert into big-endian order. This is based on the 217 | /// endianness of the UUID, rather than the target environment so bytes will be flipped on both 218 | /// big and little endian machines. 219 | #[inline] 220 | #[must_use] 221 | pub const fn from_u128_le(value: u128) -> Self { 222 | Self { 223 | uuid: Uuid::from_u128_le(value), 224 | _phantom: PhantomData, 225 | } 226 | } 227 | 228 | /// Creates a UUID from two 64bit values. 229 | #[inline] 230 | #[must_use] 231 | pub const fn from_u64_pair(d1: u64, d2: u64) -> Self { 232 | Self { 233 | uuid: Uuid::from_u64_pair(d1, d2), 234 | _phantom: PhantomData, 235 | } 236 | } 237 | 238 | /// Creates a UUID using the supplied bytes. 239 | #[inline] 240 | #[must_use] 241 | pub const fn from_bytes(bytes: uuid::Bytes) -> Self { 242 | Self { 243 | uuid: Uuid::from_bytes(bytes), 244 | _phantom: PhantomData, 245 | } 246 | } 247 | 248 | /// Creates a UUID using the supplied bytes in little-endian order. 249 | /// 250 | /// The individual fields encoded in the buffer will be flipped. 251 | #[inline] 252 | #[must_use] 253 | pub const fn from_bytes_le(bytes: uuid::Bytes) -> Self { 254 | Self { 255 | uuid: Uuid::from_bytes_le(bytes), 256 | _phantom: PhantomData, 257 | } 258 | } 259 | 260 | /// Creates a new, random UUID v4 of this type. 261 | #[inline] 262 | #[cfg(feature = "v4")] 263 | #[must_use] 264 | pub fn new_v4() -> Self { 265 | Self::from_untyped_uuid(Uuid::new_v4()) 266 | } 267 | 268 | /// Returns the version number of the UUID. 269 | /// 270 | /// This represents the algorithm used to generate the value. 271 | /// This method is the future-proof alternative to [`Self::get_version`]. 272 | /// 273 | /// # References 274 | /// 275 | /// * [Version Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.2) 276 | #[inline] 277 | pub const fn get_version_num(&self) -> usize { 278 | self.uuid.get_version_num() 279 | } 280 | 281 | /// Returns the version of the UUID. 282 | /// 283 | /// This represents the algorithm used to generate the value. 284 | /// If the version field doesn't contain a recognized version then `None` 285 | /// is returned. If you're trying to read the version for a future extension 286 | /// you can also use [`Uuid::get_version_num`] to unconditionally return a 287 | /// number. Future extensions may start to return `Some` once they're 288 | /// standardized and supported. 289 | /// 290 | /// # References 291 | /// 292 | /// * [Version Field in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-4.2) 293 | #[inline] 294 | pub fn get_version(&self) -> Option { 295 | self.uuid.get_version() 296 | } 297 | } 298 | 299 | // --- 300 | // Trait impls 301 | // --- 302 | 303 | impl PartialEq for TypedUuid { 304 | #[inline] 305 | fn eq(&self, other: &Self) -> bool { 306 | self.uuid.eq(&other.uuid) 307 | } 308 | } 309 | 310 | impl Eq for TypedUuid {} 311 | 312 | impl PartialOrd for TypedUuid { 313 | #[inline] 314 | fn partial_cmp(&self, other: &Self) -> Option { 315 | Some(self.uuid.cmp(&other.uuid)) 316 | } 317 | } 318 | 319 | impl Ord for TypedUuid { 320 | #[inline] 321 | fn cmp(&self, other: &Self) -> core::cmp::Ordering { 322 | self.uuid.cmp(&other.uuid) 323 | } 324 | } 325 | 326 | impl Hash for TypedUuid { 327 | #[inline] 328 | fn hash(&self, state: &mut H) { 329 | self.uuid.hash(state); 330 | } 331 | } 332 | 333 | impl fmt::Debug for TypedUuid { 334 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 335 | self.uuid.fmt(f)?; 336 | write!(f, " ({})", T::tag()) 337 | } 338 | } 339 | 340 | impl fmt::Display for TypedUuid { 341 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 342 | self.uuid.fmt(f) 343 | } 344 | } 345 | 346 | impl Clone for TypedUuid { 347 | #[inline] 348 | fn clone(&self) -> Self { 349 | *self 350 | } 351 | } 352 | 353 | impl Copy for TypedUuid {} 354 | 355 | impl FromStr for TypedUuid { 356 | type Err = ParseError; 357 | 358 | fn from_str(s: &str) -> Result { 359 | let uuid = Uuid::from_str(s).map_err(|error| ParseError { 360 | error, 361 | tag: T::tag(), 362 | })?; 363 | Ok(Self::from_untyped_uuid(uuid)) 364 | } 365 | } 366 | 367 | impl Default for TypedUuid { 368 | #[inline] 369 | fn default() -> Self { 370 | Self::from_untyped_uuid(Uuid::default()) 371 | } 372 | } 373 | 374 | impl AsRef<[u8]> for TypedUuid { 375 | #[inline] 376 | fn as_ref(&self) -> &[u8] { 377 | self.uuid.as_ref() 378 | } 379 | } 380 | 381 | #[cfg(feature = "alloc")] 382 | impl From> for alloc::vec::Vec { 383 | #[inline] 384 | fn from(typed_uuid: TypedUuid) -> Self { 385 | typed_uuid.into_untyped_uuid().into_bytes().to_vec() 386 | } 387 | } 388 | 389 | #[cfg(feature = "schemars08")] 390 | mod schemars08_imp { 391 | use super::*; 392 | use schemars::JsonSchema; 393 | 394 | /// Implements `JsonSchema` for `TypedUuid`, if `T` implements `JsonSchema`. 395 | /// 396 | /// * `schema_name` is set to `"TypedUuidFor"`, concatenated by the schema name of `T`. 397 | /// * `schema_id` is set to `format!("newtype_uuid::TypedUuid<{}>", T::schema_id())`. 398 | /// * `json_schema` is the same as the one for `Uuid`. 399 | impl JsonSchema for TypedUuid 400 | where 401 | T: TypedUuidKind + JsonSchema, 402 | { 403 | #[inline] 404 | fn schema_name() -> String { 405 | format!("TypedUuidFor{}", T::schema_name()) 406 | } 407 | 408 | #[inline] 409 | fn schema_id() -> std::borrow::Cow<'static, str> { 410 | std::borrow::Cow::Owned(format!("newtype_uuid::TypedUuid<{}>", T::schema_id())) 411 | } 412 | 413 | #[inline] 414 | fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { 415 | Uuid::json_schema(gen) 416 | } 417 | } 418 | } 419 | 420 | #[cfg(feature = "proptest1")] 421 | mod proptest1_imp { 422 | use super::*; 423 | use proptest::{ 424 | arbitrary::{any, Arbitrary}, 425 | strategy::{BoxedStrategy, Strategy}, 426 | }; 427 | 428 | /// Parameters for use with `proptest` instances. 429 | /// 430 | /// This is currently not exported as a type because it has no options. But 431 | /// it's left in as an extension point for the future. 432 | #[derive(Clone, Debug, Default)] 433 | pub struct TypedUuidParams(()); 434 | 435 | /// Generates random `TypedUuid` instances. 436 | /// 437 | /// Currently, this always returns a version 4 UUID. Support for other kinds 438 | /// of UUIDs might be added via [`Self::Parameters`] in the future. 439 | impl Arbitrary for TypedUuid 440 | where 441 | T: TypedUuidKind, 442 | { 443 | type Parameters = TypedUuidParams; 444 | type Strategy = BoxedStrategy; 445 | 446 | fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { 447 | let bytes = any::<[u8; 16]>(); 448 | bytes 449 | .prop_map(|b| { 450 | let uuid = uuid::Builder::from_random_bytes(b).into_uuid(); 451 | TypedUuid::::from_untyped_uuid(uuid) 452 | }) 453 | .boxed() 454 | } 455 | } 456 | } 457 | 458 | /// Represents marker types that can be used as a type parameter for [`TypedUuid`]. 459 | /// 460 | /// Generally, an implementation of this will be a zero-sized type that can never be constructed. An 461 | /// empty struct or enum works well for this. 462 | /// 463 | /// # Implementations 464 | /// 465 | /// If the `schemars08` feature is enabled, and [`JsonSchema`] is implemented for a kind `T`, then 466 | /// [`TypedUuid`]`` will also implement [`JsonSchema`]. 467 | /// 468 | /// # Notes 469 | /// 470 | /// If you have a large number of UUID kinds, it can be repetitive to implement this trait for each 471 | /// kind. Here's a template for a macro that can help: 472 | /// 473 | /// ``` 474 | /// use newtype_uuid::{TypedUuidKind, TypedUuidTag}; 475 | /// 476 | /// macro_rules! impl_typed_uuid_kind { 477 | /// ($($kind:ident => $tag:literal),* $(,)?) => { 478 | /// $( 479 | /// pub enum $kind {} 480 | /// 481 | /// impl TypedUuidKind for $kind { 482 | /// #[inline] 483 | /// fn tag() -> TypedUuidTag { 484 | /// const TAG: TypedUuidTag = TypedUuidTag::new($tag); 485 | /// TAG 486 | /// } 487 | /// } 488 | /// )* 489 | /// }; 490 | /// } 491 | /// 492 | /// // Invoke this macro with: 493 | /// impl_typed_uuid_kind! { 494 | /// Kind1 => "kind1", 495 | /// Kind2 => "kind2", 496 | /// } 497 | /// ``` 498 | /// 499 | /// [`JsonSchema`]: schemars::JsonSchema 500 | pub trait TypedUuidKind: Send + Sync + 'static { 501 | /// Returns the corresponding tag for this kind. 502 | /// 503 | /// The tag forms a runtime representation of this type. 504 | /// 505 | /// The tag is required to be a static string. 506 | fn tag() -> TypedUuidTag; 507 | } 508 | 509 | /// Describes what kind of [`TypedUuid`] something is. 510 | /// 511 | /// This is the runtime equivalent of [`TypedUuidKind`]. 512 | #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 513 | pub struct TypedUuidTag(&'static str); 514 | 515 | impl TypedUuidTag { 516 | /// Creates a new `TypedUuidTag` from a static string. 517 | /// 518 | /// The string must be non-empty, and consist of: 519 | /// - ASCII letters 520 | /// - digits (only after the first character) 521 | /// - underscores 522 | /// - hyphens (only after the first character) 523 | /// 524 | /// # Panics 525 | /// 526 | /// Panics if the above conditions aren't met. Use [`Self::try_new`] to handle errors instead. 527 | #[must_use] 528 | pub const fn new(tag: &'static str) -> Self { 529 | match Self::try_new_impl(tag) { 530 | Ok(tag) => tag, 531 | Err(message) => panic!("{}", message), 532 | } 533 | } 534 | 535 | /// Attempts to create a new `TypedUuidTag` from a static string. 536 | /// 537 | /// The string must be non-empty, and consist of: 538 | /// - ASCII letters 539 | /// - digits (only after the first character) 540 | /// - underscores 541 | /// - hyphens (only after the first character) 542 | /// 543 | /// # Errors 544 | /// 545 | /// Returns a [`TagError`] if the above conditions aren't met. 546 | pub const fn try_new(tag: &'static str) -> Result { 547 | match Self::try_new_impl(tag) { 548 | Ok(tag) => Ok(tag), 549 | Err(message) => Err(TagError { 550 | input: tag, 551 | message, 552 | }), 553 | } 554 | } 555 | 556 | const fn try_new_impl(tag: &'static str) -> Result { 557 | if tag.is_empty() { 558 | return Err("tag must not be empty"); 559 | } 560 | 561 | let bytes = tag.as_bytes(); 562 | if !(bytes[0].is_ascii_alphabetic() || bytes[0] == b'_') { 563 | return Err("first character of tag must be an ASCII letter or underscore"); 564 | } 565 | 566 | let mut bytes = match bytes { 567 | [_, rest @ ..] => rest, 568 | [] => panic!("already checked that it's non-empty"), 569 | }; 570 | while let [rest @ .., last] = &bytes { 571 | if !(last.is_ascii_alphanumeric() || *last == b'_' || *last == b'-') { 572 | break; 573 | } 574 | bytes = rest; 575 | } 576 | 577 | if !bytes.is_empty() { 578 | return Err("tag must only contain ASCII letters, digits, underscores, or hyphens"); 579 | } 580 | 581 | Ok(Self(tag)) 582 | } 583 | 584 | /// Returns the tag as a string. 585 | pub const fn as_str(&self) -> &'static str { 586 | self.0 587 | } 588 | } 589 | 590 | impl fmt::Display for TypedUuidTag { 591 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 592 | f.write_str(self.0) 593 | } 594 | } 595 | 596 | impl AsRef for TypedUuidTag { 597 | fn as_ref(&self) -> &str { 598 | self.0 599 | } 600 | } 601 | 602 | /// An error that occurred while creating a [`TypedUuidTag`]. 603 | #[derive(Clone, Debug)] 604 | #[non_exhaustive] 605 | pub struct TagError { 606 | /// The input string. 607 | pub input: &'static str, 608 | 609 | /// The error message. 610 | pub message: &'static str, 611 | } 612 | 613 | impl fmt::Display for TagError { 614 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 615 | write!( 616 | f, 617 | "error creating tag from '{}': {}", 618 | self.input, self.message 619 | ) 620 | } 621 | } 622 | 623 | #[cfg(feature = "std")] 624 | impl std::error::Error for TagError {} 625 | 626 | /// An error that occurred while parsing a [`TypedUuid`]. 627 | #[derive(Clone, Debug)] 628 | #[non_exhaustive] 629 | pub struct ParseError { 630 | /// The underlying error. 631 | pub error: uuid::Error, 632 | 633 | /// The tag of the UUID that failed to parse. 634 | pub tag: TypedUuidTag, 635 | } 636 | 637 | impl fmt::Display for ParseError { 638 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 639 | write!(f, "error parsing UUID ({})", self.tag) 640 | } 641 | } 642 | 643 | #[cfg(feature = "std")] 644 | impl std::error::Error for ParseError { 645 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 646 | Some(&self.error) 647 | } 648 | } 649 | 650 | /// A trait abstracting over typed and untyped UUIDs. 651 | /// 652 | /// This can be used to write code that's generic over [`TypedUuid`], [`Uuid`], and other types that 653 | /// may wrap [`TypedUuid`] (due to e.g. orphan rules). 654 | /// 655 | /// This trait is similar to `From`, but a bit harder to get wrong -- in general, the conversion 656 | /// from and to untyped UUIDs should be careful and explicit. 657 | pub trait GenericUuid { 658 | /// Creates a new instance of `Self` from an untyped [`Uuid`]. 659 | #[must_use] 660 | fn from_untyped_uuid(uuid: Uuid) -> Self 661 | where 662 | Self: Sized; 663 | 664 | /// Converts `self` into an untyped [`Uuid`]. 665 | #[must_use] 666 | fn into_untyped_uuid(self) -> Uuid 667 | where 668 | Self: Sized; 669 | 670 | /// Returns the inner [`Uuid`]. 671 | /// 672 | /// Generally, [`into_untyped_uuid`](Self::into_untyped_uuid) should be preferred. However, 673 | /// in some cases it may be necessary to use this method to satisfy lifetime constraints. 674 | fn as_untyped_uuid(&self) -> &Uuid; 675 | } 676 | 677 | impl GenericUuid for Uuid { 678 | #[inline] 679 | fn from_untyped_uuid(uuid: Uuid) -> Self { 680 | uuid 681 | } 682 | 683 | #[inline] 684 | fn into_untyped_uuid(self) -> Uuid { 685 | self 686 | } 687 | 688 | #[inline] 689 | fn as_untyped_uuid(&self) -> &Uuid { 690 | self 691 | } 692 | } 693 | 694 | impl GenericUuid for TypedUuid { 695 | #[inline] 696 | fn from_untyped_uuid(uuid: Uuid) -> Self { 697 | Self { 698 | uuid, 699 | _phantom: PhantomData, 700 | } 701 | } 702 | 703 | #[inline] 704 | fn into_untyped_uuid(self) -> Uuid { 705 | self.uuid 706 | } 707 | 708 | #[inline] 709 | fn as_untyped_uuid(&self) -> &Uuid { 710 | &self.uuid 711 | } 712 | } 713 | 714 | #[cfg(test)] 715 | mod tests { 716 | use super::*; 717 | 718 | #[test] 719 | fn test_validate_tags() { 720 | for &valid_tag in &[ 721 | "a", "a-", "a_", "a-b", "a_b", "a1", "a1-", "a1_", "a1-b", "a1_b", "_a", 722 | ] { 723 | TypedUuidTag::try_new(valid_tag).expect("tag is valid"); 724 | // Should not panic 725 | _ = TypedUuidTag::new(valid_tag); 726 | } 727 | 728 | for invalid_tag in &["", "1", "-", "a1b!", "a1-b!", "a1_b:", "\u{1f4a9}"] { 729 | TypedUuidTag::try_new(invalid_tag).unwrap_err(); 730 | } 731 | } 732 | 733 | // This test just ensures that `GenericUuid` is object-safe. 734 | #[test] 735 | #[cfg(all(feature = "v4", feature = "std"))] 736 | fn test_generic_uuid_object_safe() { 737 | let uuid = Uuid::new_v4(); 738 | let box_uuid = Box::new(uuid) as Box; 739 | assert_eq!(box_uuid.as_untyped_uuid(), &uuid); 740 | } 741 | } 742 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | sign-tag = true 2 | # Required for templates below to work 3 | consolidate-commits = false 4 | pre-release-commit-message = "[{{crate_name}}] version {{version}}" 5 | tag-message = "[{{crate_name}}] version {{version}}" 6 | tag-name = "newtype-uuid-{{version}}" 7 | publish = false 8 | dependent-version = "upgrade" 9 | -------------------------------------------------------------------------------- /scripts/commands.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e -o pipefail 4 | 5 | # Run commands to build and test with a feature powerset. Requires `cargo-hack` to be installed. 6 | 7 | CARGO="${CARGO:-cargo}" 8 | EXCLUDED_FEATURES_BY_DEFAULT=(internal-schemars08-tests internal-proptest1-tests) 9 | EXCLUDED_FEATURES_NO_STD=(schemars08 serde default std alloc v4 proptest1) 10 | 11 | trap 'echo_err "Error occurred at $0 command: $BASH_COMMAND"' ERR 12 | trap 'echo_err "Exiting $0"' EXIT 13 | 14 | run_build() { 15 | check_cargo_hack 16 | 17 | echo_err "Running non-dev build" >&2 18 | run_cargo_hack build 19 | 20 | echo_err "Running dev build" 21 | run_cargo_hack build --all-targets 22 | } 23 | 24 | run_nextest() { 25 | check_cargo_hack 26 | 27 | echo_err "Running non-doc tests" 28 | # Some configurations of cargo-hack cause no tests to be run. This is expected. 29 | run_cargo_hack nextest run --all-targets --no-tests=pass 30 | } 31 | 32 | run_nextest_all_features() { 33 | check_cargo_hack 34 | 35 | echo_err "Running non-doc tests with all features" 36 | cargo nextest run --all-targets --all-features 37 | } 38 | 39 | run_doctest() { 40 | echo_err "Running doctests with all features" 41 | cargo test --all-features --doc 42 | } 43 | 44 | run_coverage() { 45 | echo_err "Running coverage (requires nightly)" 46 | run_cargo_std llvm-cov nextest --all-features --all-targets --lcov --output-path lcov.info 47 | run_cargo_std llvm-cov test --all-features --doc --lcov --output-path lcov-doctest.info 48 | echo_err "Wrote output to lcov.info and lcov-doctest.info" 49 | } 50 | 51 | run_build_no_std() { 52 | local build_target="$1" 53 | 54 | check_cargo_hack 55 | 56 | echo_err "Building for no-std target ${build_target}" 57 | run_cargo_hack_no_std build --target "${build_target}" 58 | } 59 | 60 | echo_err() { 61 | echo "$@" >&2 62 | } 63 | 64 | check_cargo_hack() { 65 | if ! $CARGO hack --version >/dev/null 2>&1; then 66 | echo_err "cargo-hack not installed. Install it with:" 67 | echo_err " cargo install cargo-hack" 68 | exit 1 69 | fi 70 | } 71 | 72 | run_cargo_hack() { 73 | joined_excluded_features=$(printf ",%s" "${EXCLUDED_FEATURES_BY_DEFAULT[@]}") 74 | # Strip leading comma 75 | joined_excluded_features=${joined_excluded_features:1} 76 | 77 | $CARGO hack --feature-powerset --exclude-features "$joined_excluded_features" "$@" 78 | } 79 | 80 | run_cargo_hack_no_std() { 81 | joined_excluded_features=$(printf ",%s" "${EXCLUDED_FEATURES_NO_STD[@]}") 82 | # Strip leading comma 83 | joined_excluded_features=${joined_excluded_features:1} 84 | 85 | $CARGO hack --workspace --exclude integration-tests --feature-powerset --exclude-features "$joined_excluded_features" "$@" 86 | } 87 | 88 | run_cargo_std() { 89 | $CARGO "$@" --features std 90 | } 91 | 92 | if [[ $# -eq 0 ]]; then 93 | echo_err "Usage: commands.sh [b|build|t|test|nt|nextest|dt|doctest|miri|coverage|build-no-std]" 94 | exit 1 95 | fi 96 | 97 | while [[ "$#" -gt 0 ]]; do 98 | case $1 in 99 | +*) CARGO="$CARGO $1" ;; 100 | b|build) run_build ;; 101 | nt|nextest) run_nextest ;; 102 | nta|nextest-all-features) run_nextest_all_features ;; 103 | coverage) run_coverage ;; 104 | dt|doctest) run_doctest ;; 105 | build-no-std) 106 | shift; 107 | case $1 in 108 | --target) build_target="$2"; shift ;; 109 | "") echo_err "Usage: commands.sh build-no-std --target "; exit 1 ;; 110 | esac 111 | 112 | if [[ -z "${build_target:-}" ]]; then 113 | echo_err "Usage: commands.sh build-no-std --target " 114 | exit 1 115 | fi 116 | 117 | run_build_no_std "$build_target" ;; 118 | -h|--help) echo "Usage: commands.sh [b|build|t|test|nt|nextest|dt|doctest|miri|coverage|build-no-std]"; exit 0 ;; 119 | *) echo "Unknown parameter passed: $1"; exit 1 ;; 120 | esac 121 | shift 122 | done 123 | -------------------------------------------------------------------------------- /scripts/fix-readmes.awk: -------------------------------------------------------------------------------- 1 | # Fix up readmes: 2 | # * Replace ## with # in code blocks. 3 | # * Remove [] without a following () from output. 4 | 5 | BEGIN { 6 | true = 1 7 | false = 0 8 | in_block = false 9 | } 10 | 11 | { 12 | if (!in_block && $0 ~ /^```/) { 13 | in_block = true 14 | } else if (in_block && $0 ~ /^```$/) { 15 | in_block = false 16 | } 17 | 18 | if (in_block) { 19 | sub(/## /, "# ") 20 | print $0 21 | } else { 22 | # Strip [] without a () that immediately follows them from 23 | # the output. 24 | subbed = gensub(/\[([^\[]+)]([^\(]|$)/, "\\1\\2", "g") 25 | print subbed 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/regenerate-readmes.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) The cargo-guppy Contributors 4 | # SPDX-License-Identifier: MIT OR Apache-2.0 5 | 6 | # Regenerate readme files in this repository. 7 | 8 | set -eo pipefail 9 | 10 | cd "$(git rev-parse --show-toplevel)" 11 | git ls-files | grep README.tpl$ | while read -r readme; do 12 | dir=$(dirname "$readme") 13 | cargo readme --project-root "$dir" > "$dir/README.md.tmp" 14 | gawk -f "scripts/fix-readmes.awk" "$dir/README.md.tmp" > "$dir/README.md" 15 | rm "$dir/README.md.tmp" 16 | done 17 | --------------------------------------------------------------------------------