diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df2b7ef..d6197d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,8 +48,8 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - # 1.85 is the MSRV. - rust-version: ["1.85", "stable"] + # 1.88 is the MSRV. + rust-version: ["1.88", "stable"] fail-fast: false env: RUSTFLAGS: -D warnings diff --git a/Cargo.lock b/Cargo.lock index 337ec68..e050956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,24 +2,58 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "atomicwrites" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef1bb8d1b645fe38d51dfc331d720fb5fc2c94b440c76cc79c80ff265ca33e3" +dependencies = [ + "rustix 0.38.44", + "tempfile", + "windows-sys 0.52.0", +] + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + [[package]] name = "byte-wrapper" version = "0.1.0" dependencies = [ "base64", "ciborium", + "expectorate", "hex", "hex-literal", + "prettyplease", + "quote", "schemars", "serde", "serde_core", "serde_json", + "syn", + "typify-impl", ] [[package]] @@ -55,6 +89,19 @@ dependencies = [ "half", ] +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -67,6 +114,71 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "expectorate" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfe29c067b3dd398703f5cb05420a21c21079edfbcfa96c3ff2d9bde55cc8b3" +dependencies = [ + "atomicwrites", + "console", + "newline-converter", + "similar", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "half" version = "2.7.1" @@ -78,6 +190,32 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -90,18 +228,91 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + [[package]] name = "itoa" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "newline-converter" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -120,6 +331,48 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "regress" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2057b2325e68a893284d1538021ab90279adac1139957ca2a74426c6f118fb48" +dependencies = [ + "hashbrown 0.16.1", + "memchr", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -144,6 +397,12 @@ dependencies = [ "syn", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -198,6 +457,12 @@ dependencies = [ "zmij", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "syn" version = "2.0.114" @@ -209,12 +474,326 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typify-impl" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fd0d27608a466d063d23b97cf2d26c25d838f01b4f7d5ff406a7446f16b6e3" +dependencies = [ + "heck", + "log", + "proc-macro2", + "quote", + "regress", + "schemars", + "semver", + "serde", + "serde_json", + "syn", + "thiserror", + "unicode-ident", +] + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "zerocopy" version = "0.8.33" diff --git a/Cargo.toml b/Cargo.toml index cf2132d..959cff2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/oxidecomputer/byte-wrapper" documentation = "https://docs.rs/byte-wrapper" edition = "2024" -rust-version = "1.85" +rust-version = "1.88" keywords = ["bytes", "hex", "base64", "serde", "no_std"] categories = ["encoding", "no-std"] @@ -36,7 +36,7 @@ default = ["base64", "hex"] alloc = ["serde_core?/alloc"] base64 = ["alloc", "dep:base64"] hex = ["dep:hex"] -schemars08 = ["alloc", "dep:schemars08"] +schemars08 = ["alloc", "dep:schemars08", "dep:serde_json"] serde = ["dep:serde_core"] [dependencies] @@ -44,9 +44,15 @@ base64 = { version = "0.22", optional = true } hex = { version = "0.4", default-features = false, optional = true } schemars08 = { package = "schemars", version = "0.8", optional = true } serde_core = { version = "1", default-features = false, optional = true } +serde_json = { version = "1", optional = true } [dev-dependencies] hex-literal = "1" serde = { version = "1", default-features = false, features = ["derive"] } serde_json = "1" ciborium = "0.2" +expectorate = "1" +prettyplease = "0.2" +quote = "1" +syn = "2" +typify-impl = "0.6" diff --git a/README.md b/README.md index b63240f..24acf18 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/byte-wrapper.svg?) [![crates.io](https://img.shields.io/crates/v/byte-wrapper.svg?logo=rust)](https://crates.io/crates/byte-wrapper) [![docs.rs](https://img.shields.io/docsrs/byte-wrapper.svg?logo=docs.rs)](https://docs.rs/byte-wrapper) -[![Rust: ^1.85.0](https://img.shields.io/badge/rust-^1.85.0-93450a.svg?logo=rust)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) +[![Rust: ^1.88.0](https://img.shields.io/badge/rust-^1.88.0-93450a.svg?logo=rust)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) @@ -24,6 +24,11 @@ formats like JSON, and as efficient raw bytes in binary formats like [CBOR]. You do not have to use the newtypes in your own type definitions; you can refer to them via `#[serde(with = "...")]` instead. +With the `schemars08` feature, both types implement [`JsonSchema`], +including automatic opt-in replacement with +[typify](https://crates.io/crates/typify) and +[progenitor](https://crates.io/crates/progenitor). + ## Types * [`HexArray`](https://docs.rs/byte-wrapper/0.1.0/byte_wrapper/hex_array/struct.HexArray.html) encodes a fixed-length byte array as a hex @@ -111,6 +116,7 @@ The closest alternatives are: *Not enabled by default.* [CBOR]: https://cbor.io/ +[`JsonSchema`]: https://docs.rs/schemars/0.8/schemars/trait.JsonSchema.html [`serde-human-bytes`]: https://docs.rs/serde-human-bytes [`serde-encoded-bytes`]: https://docs.rs/serde-encoded-bytes [`serde_with`]: https://docs.rs/serde_with @@ -121,7 +127,6 @@ The closest alternatives are: [`Display`]: https://doc.rust-lang.org/nightly/core/fmt/trait.Display.html [`FromStr`]: https://doc.rust-lang.org/nightly/core/str/traits/trait.FromStr.html [`Deref`]: https://doc.rust-lang.org/nightly/core/ops/deref/trait.Deref.html -[`JsonSchema`]: https://docs.rs/schemars/0.8/schemars/trait.JsonSchema.html ## License diff --git a/src/base64_vec.rs b/src/base64_vec.rs index 971782d..c626e20 100644 --- a/src/base64_vec.rs +++ b/src/base64_vec.rs @@ -374,6 +374,7 @@ mod serde_impls { #[cfg(feature = "schemars08")] mod schemars_impls { use super::Base64Vec; + use crate::schemars_util::x_rust_type_extension; use alloc::string::String; use schemars08::{ JsonSchema, @@ -391,12 +392,12 @@ mod schemars_impls { } fn json_schema(_generator: &mut SchemaGenerator) -> Schema { + let mut extensions = x_rust_type_extension("Base64Vec"); + extensions.insert("contentEncoding".into(), "base64".into()); Schema::Object(SchemaObject { instance_type: Some(InstanceType::String.into()), format: Some("byte".into()), - extensions: [("contentEncoding".into(), "base64".into())] - .into_iter() - .collect(), + extensions, ..Default::default() }) } diff --git a/src/hex_array.rs b/src/hex_array.rs index 6ccaa89..ef24efc 100644 --- a/src/hex_array.rs +++ b/src/hex_array.rs @@ -378,13 +378,13 @@ mod serde_impls { { // Reject early if the sequence reports a // wrong length. - if let Some(len) = seq.size_hint() { - if len != N { - return Err(Error::invalid_length( - len, - &HexExpected::, - )); - } + if let Some(len) = seq.size_hint() + && len != N + { + return Err(Error::invalid_length( + len, + &HexExpected::, + )); } let mut out = [0u8; N]; for (i, byte) in out.iter_mut().enumerate() { @@ -498,6 +498,7 @@ mod serde_impls { #[cfg(feature = "schemars08")] mod schemars_impls { use super::HexArray; + use crate::schemars_util::x_rust_type_extension; use alloc::{boxed::Box, format, string::String}; use schemars08::{ JsonSchema, @@ -523,6 +524,7 @@ mod schemars_impls { max_length: Some(hex_len as u32), pattern: Some(format!("^[0-9a-fA-F]{{{hex_len}}}$")), })), + extensions: x_rust_type_extension(&format!("HexArray::<{N}>")), ..Default::default() }) } diff --git a/src/lib.rs b/src/lib.rs index 9b191e5..586a434 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,11 @@ //! You do not have to use the newtypes in your own type definitions; you can //! refer to them via `#[serde(with = "...")]` instead. //! +//! With the `schemars08` feature, both types implement [`JsonSchema`], +//! including automatic opt-in replacement with +//! [typify](https://crates.io/crates/typify) and +//! [progenitor](https://crates.io/crates/progenitor). +//! //! [CBOR]: https://cbor.io/ //! //! # Types @@ -134,6 +139,8 @@ extern crate alloc; mod base64_vec; #[cfg(feature = "hex")] mod hex_array; +#[cfg(all(feature = "schemars08", any(feature = "base64", feature = "hex")))] +mod schemars_util; #[cfg(feature = "base64")] pub use base64_vec::{Base64Vec, ParseBase64Error}; diff --git a/src/schemars_util.rs b/src/schemars_util.rs new file mode 100644 index 0000000..480ced6 --- /dev/null +++ b/src/schemars_util.rs @@ -0,0 +1,22 @@ +// Copyright (c) The byte-wrapper Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use alloc::{format, string::String}; + +/// Builds a schemars extensions map containing the `x-rust-type` entry for the +/// given type name. The version is the earliest semver-compatible release of +/// this crate; update it only on breaking changes. +pub(crate) fn x_rust_type_extension( + type_name: &str, +) -> schemars08::Map { + [( + "x-rust-type".into(), + serde_json::json!({ + "crate": "byte-wrapper", + "version": "0.1.0", + "path": format!("byte_wrapper::{type_name}"), + }), + )] + .into_iter() + .collect() +} diff --git a/tests/integration/base64_schemars.rs b/tests/integration/base64_schemars.rs index 274d82b..62d8db5 100644 --- a/tests/integration/base64_schemars.rs +++ b/tests/integration/base64_schemars.rs @@ -13,7 +13,12 @@ fn base64_vec_schema() { "title": "Base64Vec", "type": "string", "format": "byte", - "contentEncoding": "base64" + "contentEncoding": "base64", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::Base64Vec" + } }); assert_eq!(actual, expected); } @@ -44,7 +49,12 @@ fn with_base64_vec_attr() { "data": { "type": "string", "format": "byte", - "contentEncoding": "base64" + "contentEncoding": "base64", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::Base64Vec" + } } } }); @@ -64,7 +74,12 @@ fn with_base64_vec_direct() { "data": { "type": "string", "format": "byte", - "contentEncoding": "base64" + "contentEncoding": "base64", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::Base64Vec" + } } } }); diff --git a/tests/integration/hex_schemars.rs b/tests/integration/hex_schemars.rs index bba4885..4dc13c5 100644 --- a/tests/integration/hex_schemars.rs +++ b/tests/integration/hex_schemars.rs @@ -14,7 +14,12 @@ fn hex_array_schema() { "type": "string", "maxLength": 32, "minLength": 32, - "pattern": "^[0-9a-fA-F]{32}$" + "pattern": "^[0-9a-fA-F]{32}$", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::HexArray::<16>" + } }); assert_eq!(actual, expected); } @@ -46,7 +51,12 @@ fn with_hex_array_attr() { "type": "string", "maxLength": 32, "minLength": 32, - "pattern": "^[0-9a-fA-F]{32}$" + "pattern": "^[0-9a-fA-F]{32}$", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::HexArray::<16>" + } } } }); @@ -67,7 +77,12 @@ fn with_hex_array_direct() { "type": "string", "maxLength": 32, "minLength": 32, - "pattern": "^[0-9a-fA-F]{32}$" + "pattern": "^[0-9a-fA-F]{32}$", + "x-rust-type": { + "crate": "byte-wrapper", + "version": "0.1.0", + "path": "byte_wrapper::HexArray::<16>" + } } } }); diff --git a/tests/integration/main.rs b/tests/integration/main.rs index a546301..942b810 100644 --- a/tests/integration/main.rs +++ b/tests/integration/main.rs @@ -13,3 +13,5 @@ mod hex; mod hex_schemars; #[cfg(all(feature = "hex", feature = "serde"))] mod hex_serde; +#[cfg(feature = "schemars08")] +mod typify_roundtrip; diff --git a/tests/integration/typify_roundtrip.rs b/tests/integration/typify_roundtrip.rs new file mode 100644 index 0000000..20df433 --- /dev/null +++ b/tests/integration/typify_roundtrip.rs @@ -0,0 +1,99 @@ +// Copyright (c) The byte-wrapper Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! End-to-end tests verifying that schemas produced by our `JsonSchema` +//! impls are correctly consumed by typify's `x-rust-type` replacement. + +#[cfg(feature = "base64")] +mod base64_tests { + use byte_wrapper::Base64Vec; + use schemars08::{self as schemars, JsonSchema, schema_for}; + + #[expect(dead_code)] + #[derive(JsonSchema)] + struct HasBase64Direct { + data: Base64Vec, + } + + #[test] + fn base64_direct() { + let code = super::typify_output(&schema_for!(HasBase64Direct)); + expectorate::assert_contents( + "tests/output/typify-base64-direct.rs", + &code, + ); + } + + #[expect(dead_code)] + #[derive(JsonSchema)] + struct HasBase64WithAttr { + #[schemars(with = "Base64Vec")] + data: Vec, + } + + #[test] + fn base64_with_attr() { + let code = super::typify_output(&schema_for!(HasBase64WithAttr)); + expectorate::assert_contents( + "tests/output/typify-base64-with-attr.rs", + &code, + ); + } +} + +#[cfg(feature = "hex")] +mod hex_tests { + use byte_wrapper::HexArray; + use schemars08::{self as schemars, JsonSchema, schema_for}; + + #[expect(dead_code)] + #[derive(JsonSchema)] + struct HasHexDirect { + checksum: HexArray<32>, + } + + #[test] + fn hex_direct() { + let code = super::typify_output(&schema_for!(HasHexDirect)); + expectorate::assert_contents( + "tests/output/typify-hex-direct.rs", + &code, + ); + } + + #[expect(dead_code)] + #[derive(JsonSchema)] + struct HasHexWithAttr { + #[schemars(with = "HexArray<32>")] + checksum: [u8; 32], + } + + #[test] + fn hex_with_attr() { + let code = super::typify_output(&schema_for!(HasHexWithAttr)); + expectorate::assert_contents( + "tests/output/typify-hex-with-attr.rs", + &code, + ); + } +} + +/// Feed a root schema into typify with byte-wrapper configured as a +/// known crate, format the output with prettyplease, and return it. +#[cfg(any(feature = "base64", feature = "hex"))] +fn typify_output(root_schema: &schemars08::schema::RootSchema) -> String { + use typify_impl::{CrateVers, TypeSpace, TypeSpaceSettings}; + + let mut settings = TypeSpaceSettings::default(); + settings.with_crate( + "byte-wrapper", + CrateVers::Version("0.1.0".parse().unwrap()), + None, + ); + let mut type_space = TypeSpace::new(&settings); + type_space.add_root_schema(root_schema.clone()).expect("added root schema"); + + let tokens = quote::quote! { #type_space }; + let file = syn::parse2(tokens).expect("parsed token stream"); + prettyplease::unparse(&file) +} diff --git a/tests/output/typify-base64-direct.rs b/tests/output/typify-base64-direct.rs new file mode 100644 index 0000000..faba49a --- /dev/null +++ b/tests/output/typify-base64-direct.rs @@ -0,0 +1,62 @@ +/// Error types. +pub mod error { + /// Error from a `TryFrom` or `FromStr` implementation. + pub struct ConversionError(::std::borrow::Cow<'static, str>); + impl ::std::error::Error for ConversionError {} + impl ::std::fmt::Display for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Display::fmt(&self.0, f) + } + } + impl ::std::fmt::Debug for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Debug::fmt(&self.0, f) + } + } + impl From<&'static str> for ConversionError { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + impl From for ConversionError { + fn from(value: String) -> Self { + Self(value.into()) + } + } +} +///`HasBase64Direct` +/// +///
JSON schema +/// +/// ```json +///{ +/// "title": "HasBase64Direct", +/// "type": "object", +/// "required": [ +/// "data" +/// ], +/// "properties": { +/// "data": { +/// "type": "string", +/// "format": "byte", +/// "contentEncoding": "base64", +/// "x-rust-type": { +/// "crate": "byte-wrapper", +/// "path": "byte_wrapper::Base64Vec", +/// "version": "0.1.0" +/// } +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct HasBase64Direct { + pub data: ::byte_wrapper::Base64Vec, +} diff --git a/tests/output/typify-base64-with-attr.rs b/tests/output/typify-base64-with-attr.rs new file mode 100644 index 0000000..cdfb98b --- /dev/null +++ b/tests/output/typify-base64-with-attr.rs @@ -0,0 +1,62 @@ +/// Error types. +pub mod error { + /// Error from a `TryFrom` or `FromStr` implementation. + pub struct ConversionError(::std::borrow::Cow<'static, str>); + impl ::std::error::Error for ConversionError {} + impl ::std::fmt::Display for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Display::fmt(&self.0, f) + } + } + impl ::std::fmt::Debug for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Debug::fmt(&self.0, f) + } + } + impl From<&'static str> for ConversionError { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + impl From for ConversionError { + fn from(value: String) -> Self { + Self(value.into()) + } + } +} +///`HasBase64WithAttr` +/// +///
JSON schema +/// +/// ```json +///{ +/// "title": "HasBase64WithAttr", +/// "type": "object", +/// "required": [ +/// "data" +/// ], +/// "properties": { +/// "data": { +/// "type": "string", +/// "format": "byte", +/// "contentEncoding": "base64", +/// "x-rust-type": { +/// "crate": "byte-wrapper", +/// "path": "byte_wrapper::Base64Vec", +/// "version": "0.1.0" +/// } +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct HasBase64WithAttr { + pub data: ::byte_wrapper::Base64Vec, +} diff --git a/tests/output/typify-hex-direct.rs b/tests/output/typify-hex-direct.rs new file mode 100644 index 0000000..d5c3db7 --- /dev/null +++ b/tests/output/typify-hex-direct.rs @@ -0,0 +1,63 @@ +/// Error types. +pub mod error { + /// Error from a `TryFrom` or `FromStr` implementation. + pub struct ConversionError(::std::borrow::Cow<'static, str>); + impl ::std::error::Error for ConversionError {} + impl ::std::fmt::Display for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Display::fmt(&self.0, f) + } + } + impl ::std::fmt::Debug for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Debug::fmt(&self.0, f) + } + } + impl From<&'static str> for ConversionError { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + impl From for ConversionError { + fn from(value: String) -> Self { + Self(value.into()) + } + } +} +///`HasHexDirect` +/// +///
JSON schema +/// +/// ```json +///{ +/// "title": "HasHexDirect", +/// "type": "object", +/// "required": [ +/// "checksum" +/// ], +/// "properties": { +/// "checksum": { +/// "type": "string", +/// "maxLength": 64, +/// "minLength": 64, +/// "pattern": "^[0-9a-fA-F]{64}$", +/// "x-rust-type": { +/// "crate": "byte-wrapper", +/// "path": "byte_wrapper::HexArray::<32>", +/// "version": "0.1.0" +/// } +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct HasHexDirect { + pub checksum: ::byte_wrapper::HexArray<32>, +} diff --git a/tests/output/typify-hex-with-attr.rs b/tests/output/typify-hex-with-attr.rs new file mode 100644 index 0000000..76e0c8e --- /dev/null +++ b/tests/output/typify-hex-with-attr.rs @@ -0,0 +1,63 @@ +/// Error types. +pub mod error { + /// Error from a `TryFrom` or `FromStr` implementation. + pub struct ConversionError(::std::borrow::Cow<'static, str>); + impl ::std::error::Error for ConversionError {} + impl ::std::fmt::Display for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Display::fmt(&self.0, f) + } + } + impl ::std::fmt::Debug for ConversionError { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Debug::fmt(&self.0, f) + } + } + impl From<&'static str> for ConversionError { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + impl From for ConversionError { + fn from(value: String) -> Self { + Self(value.into()) + } + } +} +///`HasHexWithAttr` +/// +///
JSON schema +/// +/// ```json +///{ +/// "title": "HasHexWithAttr", +/// "type": "object", +/// "required": [ +/// "checksum" +/// ], +/// "properties": { +/// "checksum": { +/// "type": "string", +/// "maxLength": 64, +/// "minLength": 64, +/// "pattern": "^[0-9a-fA-F]{64}$", +/// "x-rust-type": { +/// "crate": "byte-wrapper", +/// "path": "byte_wrapper::HexArray::<32>", +/// "version": "0.1.0" +/// } +/// } +/// } +///} +/// ``` +///
+#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)] +pub struct HasHexWithAttr { + pub checksum: ::byte_wrapper::HexArray<32>, +}