schemars-1.2.1/.cargo_vcs_info.json0000644000000001460000000000100126430ustar { "git": { "sha1": "5ef5da1e9aecd0e949b591fbb1832fe53fa3e8ba" }, "path_in_vcs": "schemars" }schemars-1.2.1/.gitignore000064400000000000000000000001141046102023000134160ustar 00000000000000/target **/*.rs.bk Cargo.lock /tests/actual/*.json /tests/expected/README.mdschemars-1.2.1/Cargo.lock0000644000001213670000000000100106270ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ahash" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "getrandom", "once_cell", "serde", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys", ] [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" dependencies = [ "serde", ] [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bigdecimal" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" dependencies = [ "autocfg", "libm", "num-bigint", "num-integer", "num-traits", "serde", ] [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "borrow-or-share" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" [[package]] name = "bumpalo" version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytecount" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" dependencies = [ "serde", ] [[package]] name = "castaway" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" dependencies = [ "rustversion", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "num-traits", "serde", ] [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "compact_str" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" dependencies = [ "castaway", "cfg-if", "itoa", "rustversion", "ryu", "static_assertions", ] [[package]] name = "darling" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn", ] [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", "syn", ] [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "dyn-clone" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ "serde", ] [[package]] name = "email_address" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" dependencies = [ "serde", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fancy-regex" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set", "regex-automata", "regex-syntax", ] [[package]] name = "fluent-uri" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" dependencies = [ "borrow-or-share", "ref-cast", "serde", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fraction" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" dependencies = [ "lazy_static", "num", ] [[package]] name = "garde" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a989bd2fd12136080f7825ff410d9239ce84a2a639487fc9d924ee42e2fb84f" dependencies = [ "compact_str", "garde_derive", "once_cell", "regex", "smallvec", "url", ] [[package]] name = "garde_derive" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f7f0545bbbba0a37d4d445890fa5759814e0716f02417b39f6fab292193df68" dependencies = [ "proc-macro2", "quote", "regex", "syn", ] [[package]] name = "getrandom" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", "wasi", ] [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "hashbrown" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", "serde", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde", "windows-sys", ] [[package]] name = "jiff-static" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "jiff-tzdb" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" [[package]] name = "jiff-tzdb-platform" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ "jiff-tzdb", ] [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "jsonschema" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b46a0365a611fbf1d2143104dcf910aada96fafd295bab16c60b802bf6fa1d" dependencies = [ "ahash", "base64", "bytecount", "email_address", "fancy-regex", "fraction", "idna", "itoa", "num-cmp", "num-traits", "once_cell", "percent-encoding", "referencing", "regex", "regex-syntax", "serde", "serde_json", "uuid-simd", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libm" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "litemap" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", "num-integer", "num-iter", "num-rational", "num-traits", ] [[package]] name = "num-bigint" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", ] [[package]] name = "num-cmp" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" [[package]] name = "num-complex" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-iter" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "outref" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "portable-atomic" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portable-atomic-util" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ "portable-atomic", ] [[package]] name = "pretty_assertions" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", ] [[package]] name = "proc-macro-error-attr2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "proc-macro-error2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", "syn", ] [[package]] name = "proc-macro2" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "redox_syscall" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] [[package]] name = "ref-cast" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "referencing" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8eff4fa778b5c2a57e85c5f2fe3a709c52f0e60d23146e2151cbef5893f420e" dependencies = [ "ahash", "fluent-uri", "once_cell", "parking_lot", "percent-encoding", "serde_json", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rust_decimal" version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec", "num-traits", "serde", ] [[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schemars" version = "1.2.1" dependencies = [ "arrayvec", "bigdecimal", "bytes", "chrono", "dyn-clone", "either", "garde", "indexmap", "jiff", "jsonschema", "pretty_assertions", "ref-cast", "regex", "rust_decimal", "schemars_derive", "semver", "serde", "serde_json", "serde_repr", "smallvec", "smol_str 0.2.2", "smol_str 0.3.2", "snapbox", "trybuild", "url", "uuid", "validator", ] [[package]] name = "schemars_derive" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", "syn", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_derive_internals" version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_repr" version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "similar" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "smallvec" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] [[package]] name = "smol_str" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" dependencies = [ "serde", ] [[package]] name = "smol_str" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" dependencies = [ "serde", ] [[package]] name = "snapbox" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96dcfc4581e3355d70ac2ee14cfdf81dce3d85c85f1ed9e2c1d3013f53b3436b" dependencies = [ "anstream", "anstyle", "normalize-line-endings", "serde", "serde_json", "similar", "snapbox-macros", ] [[package]] name = "snapbox-macros" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" dependencies = [ "anstream", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "target-triple" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "toml" version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "toml_write", "winnow", ] [[package]] name = "toml_write" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "trybuild" version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2" dependencies = [ "glob", "serde", "serde_derive", "serde_json", "target-triple", "termcolor", "toml", ] [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "js-sys", "serde", "wasm-bindgen", ] [[package]] name = "uuid-simd" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" dependencies = [ "outref", "uuid", "vsimd", ] [[package]] name = "validator" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" dependencies = [ "idna", "once_cell", "regex", "serde", "serde_derive", "serde_json", "url", "validator_derive", ] [[package]] name = "validator_derive" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" dependencies = [ "darling", "once_cell", "proc-macro-error2", "proc-macro2", "quote", "syn", ] [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vsimd" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys", ] [[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-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 = "winnow" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zerofrom" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn", ] schemars-1.2.1/Cargo.toml0000644000000140260000000000100106430ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.74" name = "schemars" version = "1.2.1" authors = ["Graham Esau "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Generate JSON Schemas from Rust code" homepage = "https://graham.cool/schemars/" readme = "README.md" keywords = [ "rust", "json-schema", "serde", ] categories = [ "encoding", "no-std", ] license = "MIT" repository = "https://github.com/GREsau/schemars" [package.metadata.docs.rs] all-features = true [features] _ui_test = [] default = [ "derive", "std", ] derive = ["schemars_derive"] preserve_order = ["serde_json/preserve_order"] raw_value = ["serde_json/raw_value"] std = [] [lib] name = "schemars" path = "src/lib.rs" [[example]] name = "custom_serialization" path = "examples/custom_serialization.rs" [[example]] name = "custom_settings" path = "examples/custom_settings.rs" [[example]] name = "doc_comments" path = "examples/doc_comments.rs" [[example]] name = "enum_repr" path = "examples/enum_repr.rs" [[example]] name = "from_value" path = "examples/from_value.rs" [[example]] name = "main" path = "examples/main.rs" [[example]] name = "remote_derive" path = "examples/remote_derive.rs" [[example]] name = "schemars_attrs" path = "examples/schemars_attrs.rs" [[example]] name = "serde_attrs" path = "examples/serde_attrs.rs" [[example]] name = "serialize_contract" path = "examples/serialize_contract.rs" [[example]] name = "validate" path = "examples/validate.rs" [[test]] name = "integration" path = "tests/integration/main.rs" [[test]] name = "no_std" path = "tests/no_std.rs" [[test]] name = "ui" path = "tests/ui.rs" required-features = ["_ui_test"] [dependencies.arrayvec07] version = "0.7" optional = true default-features = false package = "arrayvec" [dependencies.bigdecimal04] version = "0.4" optional = true default-features = false package = "bigdecimal" [dependencies.bytes1] version = "1.0" optional = true default-features = false package = "bytes" [dependencies.chrono04] version = "0.4.39" optional = true default-features = false package = "chrono" [dependencies.dyn-clone] version = "1.0.17" [dependencies.either1] version = "1.3" optional = true default-features = false package = "either" [dependencies.indexmap2] version = "2.2.3" optional = true default-features = false package = "indexmap" [dependencies.jiff02] version = "0.2" optional = true default-features = false package = "jiff" [dependencies.ref-cast] version = "1.0.22" [dependencies.rust_decimal1] version = "1.13" optional = true default-features = false package = "rust_decimal" [dependencies.schemars_derive] version = "=1.2.1" optional = true [dependencies.semver1] version = "1.0.9" optional = true default-features = false package = "semver" [dependencies.serde] version = "1.0.194" features = ["alloc"] default-features = false [dependencies.serde_json] version = "1.0.127" features = ["alloc"] default-features = false [dependencies.smallvec1] version = "1.0" optional = true default-features = false package = "smallvec" [dependencies.smol_str02] version = "0.2.1" optional = true default-features = false package = "smol_str" [dependencies.smol_str03] version = "0.3.2" optional = true default-features = false package = "smol_str" [dependencies.url2] version = "2.0" optional = true default-features = false package = "url" [dependencies.uuid1] version = "1.0" optional = true default-features = false package = "uuid" [dev-dependencies.arrayvec07] version = "0.7" features = ["serde"] default-features = false package = "arrayvec" [dev-dependencies.bigdecimal04] version = "0.4" features = ["serde"] default-features = false package = "bigdecimal" [dev-dependencies.bytes1] version = "1.0" features = ["serde"] default-features = false package = "bytes" [dev-dependencies.chrono04] version = "0.4" features = ["serde"] default-features = false package = "chrono" [dev-dependencies.either1] version = "1.3" features = ["serde"] default-features = false package = "either" [dev-dependencies.garde] version = "0.22" features = [ "derive", "email", "regex", "url", ] [dev-dependencies.indexmap2] version = "2.0" features = ["serde"] default-features = false package = "indexmap" [dev-dependencies.jiff02] version = "0.2" features = ["serde"] package = "jiff" [dev-dependencies.jsonschema] version = "0.30" default-features = false [dev-dependencies.pretty_assertions] version = "1.2.1" [dev-dependencies.regex] version = "1.10.6" default-features = false [dev-dependencies.rust_decimal1] version = "1" features = ["serde"] default-features = false package = "rust_decimal" [dev-dependencies.semver1] version = "1.0.9" features = ["serde"] default-features = false package = "semver" [dev-dependencies.serde] version = "1.0" features = ["derive"] [dev-dependencies.serde_repr] version = "0.1.19" [dev-dependencies.smallvec1] version = "1.0" features = ["serde"] default-features = false package = "smallvec" [dev-dependencies.smol_str02] version = "0.2.1" features = ["serde"] default-features = false package = "smol_str" [dev-dependencies.smol_str03] version = "0.3.2" features = ["serde"] default-features = false package = "smol_str" [dev-dependencies.snapbox] version = "0.6.17" features = ["json"] [dev-dependencies.trybuild] version = "1.0" [dev-dependencies.url2] version = "2.0" features = [ "serde", "std", ] default-features = false package = "url" [dev-dependencies.uuid1] version = "1.0" features = ["serde"] default-features = false package = "uuid" [dev-dependencies.validator] version = "0.20" features = ["derive"] schemars-1.2.1/Cargo.toml.orig000064400000000000000000000110231046102023000143160ustar 00000000000000[package] name = "schemars" description = "Generate JSON Schemas from Rust code" homepage = "https://graham.cool/schemars/" repository = "https://github.com/GREsau/schemars" version = "1.2.1" authors = ["Graham Esau "] edition = "2021" license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding", "no-std"] rust-version = "1.74" [dependencies] schemars_derive = { version = "=1.2.1", optional = true, path = "../schemars_derive" } serde = { version = "1.0.194", default-features = false, features = ["alloc"] } serde_json = { version = "1.0.127", default-features = false, features = ["alloc"] } dyn-clone = "1.0.17" ref-cast = "1.0.22" # optional dependencies arrayvec07 = { version = "0.7", default-features = false, optional = true, package = "arrayvec" } bigdecimal04 = { version = "0.4", default-features = false, optional = true, package = "bigdecimal" } bytes1 = { version = "1.0", default-features = false, optional = true, package = "bytes" } chrono04 = { version = "0.4.39", default-features = false, optional = true, package = "chrono" } either1 = { version = "1.3", default-features = false, optional = true, package = "either" } indexmap2 = { version = "2.2.3", default-features = false, optional = true, package = "indexmap" } jiff02 = { version = "0.2", default-features = false, optional = true, package = "jiff" } rust_decimal1 = { version = "1.13", default-features = false, optional = true, package = "rust_decimal" } semver1 = { version = "1.0.9", default-features = false, optional = true, package = "semver" } smallvec1 = { version = "1.0", default-features = false, optional = true, package = "smallvec" } smol_str02 = { version = "0.2.1", default-features = false, optional = true, package = "smol_str" } smol_str03 = { version = "0.3.2", default-features = false, optional = true, package = "smol_str" } url2 = { version = "2.0", default-features = false, optional = true, package = "url" } uuid1 = { version = "1.0", default-features = false, optional = true, package = "uuid" } [dev-dependencies] pretty_assertions = "1.2.1" trybuild = "1.0" serde = { version = "1.0", features = ["derive"] } jsonschema = { version = "0.30", default-features = false } snapbox = { version = "0.6.17", features = ["json"] } serde_repr = "0.1.19" garde = { version = "0.22", features = ["derive", "email", "regex", "url"] } validator = { version = "0.20", features = ["derive"] } regex = { version = "1.10.6", default-features = false } arrayvec07 = { version = "0.7", default-features = false, features = ["serde"], package = "arrayvec" } bigdecimal04 = { version = "0.4", default-features = false, features = ["serde"], package = "bigdecimal" } bytes1 = { version = "1.0", default-features = false, features = ["serde"], package = "bytes" } chrono04 = { version = "0.4", default-features = false, features = ["serde"], package = "chrono" } either1 = { version = "1.3", default-features = false, features = ["serde"], package = "either" } indexmap2 = { version = "2.0", default-features = false, features = ["serde"], package = "indexmap" } jiff02 = { version = "0.2", features = ["serde"], package = "jiff" } rust_decimal1 = { version = "1", default-features = false, features = ["serde"], package = "rust_decimal" } semver1 = { version = "1.0.9", default-features = false, features = ["serde"], package = "semver" } smallvec1 = { version = "1.0", default-features = false, features = ["serde"], package = "smallvec" } smol_str02 = { version = "0.2.1", default-features = false, features = ["serde"], package = "smol_str" } smol_str03 = { version = "0.3.2", default-features = false, features = ["serde"], package = "smol_str" } url2 = { version = "2.0", default-features = false, features = ["serde", "std"], package = "url" } uuid1 = { version = "1.0", default-features = false, features = ["serde"], package = "uuid" } [features] default = ["derive", "std"] # Provide impls for common standard library types like `HashMap`. # Requires a dependency on the Rust standard library. std = [] # Provide `derive(JsonSchema)` macro. derive = ["schemars_derive"] # Preserves order of properties inserted into a `Schema`. # When deriving `JsonSchema`, this ensures that the `properties` entires match # the order of the fields in the struct definition. preserve_order = ["serde_json/preserve_order"] # Implements `JsonSchema` on `serde_json::value::RawValue` raw_value = ["serde_json/raw_value"] # For internal/CI use only _ui_test = [] [[test]] name = "ui" required-features = ["_ui_test"] [package.metadata.docs.rs] all-features = true schemars-1.2.1/LICENSE000064400000000000000000000020541046102023000124400ustar 00000000000000MIT License Copyright (c) 2019 Graham Esau Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. schemars-1.2.1/README.md000064400000000000000000000235301046102023000127140ustar 00000000000000# Schemars [![CI Build](https://img.shields.io/github/actions/workflow/status/GREsau/schemars/ci.yml?branch=master&logo=GitHub)](https://github.com/GREsau/schemars/actions) [![Crates.io](https://img.shields.io/crates/v/schemars)](https://crates.io/crates/schemars) [![API Docs](https://img.shields.io/docsrs/schemars/latest?label=API%20docs)](https://docs.rs/schemars/latest) [![Usage Docs](https://img.shields.io/badge/Usage%20docs-graham.cool%2Fschemars-blue)](https://graham.cool/schemars) [![MSRV 1.74+](https://img.shields.io/badge/msrv-1.74-blue)](https://blog.rust-lang.org/2023/11/16/Rust-1.74.0/) Generate JSON Schema documents from Rust code ## Basic Usage _For more detailed information, see the full [API documentation on docs.rs](https://docs.rs/schemars/latest), and the [detailed usage documentation website](https://graham.cool/schemars)._ If you don't really care about the specifics, the easiest way to generate a JSON schema for your types is to `#[derive(JsonSchema)]` and use the `schema_for!` macro. All fields of the type must also implement `JsonSchema` - Schemars implements this for many standard library types. ```rust use schemars::{schema_for, JsonSchema}; #[derive(JsonSchema)] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(JsonSchema)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); ```
Click to see the output JSON schema... ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer", "format": "int32" }, "my_nullable_enum": { "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ] } }, "required": ["my_int", "my_bool"], "$defs": { "MyEnum": { "oneOf": [ { "type": "object", "properties": { "StringNewType": { "type": "string" } }, "additionalProperties": false, "required": ["StringNewType"] }, { "type": "object", "properties": { "StructVariant": { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" } } }, "required": ["floats"] } }, "additionalProperties": false, "required": ["StructVariant"] } ] } } } ```
### Serde Compatibility One of the main aims of this library is compatibility with [Serde](https://github.com/serde-rs/serde). Any generated schema _should_ match how [serde_json](https://github.com/serde-rs/json) would serialize/deserialize to/from JSON. To support this, Schemars will check for any `#[serde(...)]` attributes on types that derive `JsonSchema`, and adjust the generated schema accordingly. ```rust use schemars::{schema_for, JsonSchema}; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct MyStruct { #[serde(rename = "myNumber")] pub my_int: i32, pub my_bool: bool, #[serde(default)] pub my_nullable_enum: Option, } #[derive(Deserialize, Serialize, JsonSchema)] #[serde(untagged)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); ```
Click to see the output JSON schema... ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "myBool": { "type": "boolean" }, "myNullableEnum": { "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ], "default": null }, "myNumber": { "type": "integer", "format": "int32" } }, "additionalProperties": false, "required": ["myNumber", "myBool"], "$defs": { "MyEnum": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" } } }, "required": ["floats"] } ] } } } ```
`#[serde(...)]` attributes can be overriden using `#[schemars(...)]` attributes, which behave identically (e.g. `#[schemars(rename_all = "camelCase")]`). You may find this useful if you want to change the generated schema without affecting Serde's behaviour, or if you're just not using Serde. ### Schema from Example Value If you want a schema for a type that can't/doesn't implement `JsonSchema`, but does implement `serde::Serialize`, then you can generate a JSON schema from a value of that type. However, this schema will generally be less precise than if the type implemented `JsonSchema` - particularly when it involves enums, since schemars will not make any assumptions about the structure of an enum based on a single variant. ```rust use schemars::schema_for_value; use serde::Serialize; #[derive(Serialize)] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(Serialize)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } let schema = schema_for_value!(MyStruct { my_int: 123, my_bool: true, my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string())) }); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); ```
Click to see the output JSON schema... ```json { "$schema": "http://json-schema.org/draft-07/schema#", "title": "MyStruct", "examples": [ { "my_bool": true, "my_int": 123, "my_nullable_enum": { "StringNewType": "foo" } } ], "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer" }, "my_nullable_enum": true } } ```
## Versioning and Stability Schemars follows semantic versioning, with the following caveats: - Increasing MSRV (Minimum Supported Rust Version) is considered a semver-minor change. Schemars aims to support the past year of stable rust versions, but this is not guaranteed. - External libraries that are supported via optional dependencies (see [Feature Flags](#feature-flags)) _may_ be removed in a minor version change, particularly if a newer semver-incompatible version has been released for a long time. - The exact structure of generated schemas (both for built-in implementations on standard library types, and for `#[derive(JsonSchema)]` implementations) may change between versions of schemars - this is not considered a breaking change. - Exported items that are marked with `#[doc(hidden)]` and have names beginning with `_` are not part of the public API, and may be changed or removed without notice. - If a bug is found in schemars that causes attributes to be incorrectly processed or silently ignored by `#[derive(JsonSchema)]`, a subsequent version of schemars may instead fail compilation when encountering such attributes. This is considered a bug fix, and not a breaking change. ## Feature Flags - `std` (enabled by default) - implements `JsonSchema` for types in the rust standard library (`JsonSchema` is still implemented on types in `core` and `alloc`, even when this feature is disabled). Disable this feature to use schemars in `no_std` environments. - `derive` (enabled by default) - provides `#[derive(JsonSchema)]` macro - `preserve_order` - keep the order of struct fields in `Schema` properties - `raw_value` - implements `JsonSchema` for `serde_json::value::RawValue` (enables the serde_json `raw_value` feature) Schemars can implement `JsonSchema` on types from several popular crates, enabled via feature flags (dependency versions are shown in brackets): - `arrayvec07` - [arrayvec](https://crates.io/crates/arrayvec) (^0.7) - `bigdecimal04` - [bigdecimal](https://crates.io/crates/bigdecimal) (^0.4) - `bytes1` - [bytes](https://crates.io/crates/bytes) (^1.0) - `chrono04` - [chrono](https://crates.io/crates/chrono) (^0.4) - `either1` - [either](https://crates.io/crates/either) (^1.3) - `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0) - `jiff02` - [jiff](https://crates.io/crates/jiff) (^0.2) - `rust_decimal1` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0) - `semver1` - [semver](https://crates.io/crates/semver) (^1.0.9) - `smallvec1` - [smallvec](https://crates.io/crates/smallvec) (^1.0) - `smol_str02` - [smol_str](https://crates.io/crates/smol_str) (^0.2.1) - `smol_str03` - [smol_str](https://crates.io/crates/smol_str) (^0.3) - `url2` - [url](https://crates.io/crates/url) (^2.0) - `uuid1` - [uuid](https://crates.io/crates/uuid) (^1.0) Bear in mind that each of these feature flags _may_ be removed in a future semver-minor change of Schemars, particularly if a newer semver-incompatible version of the external library has been released for a long time. This is unfortunately necessary to avoid supporting old/unmaintained libraries indefinitely. For example, to implement `JsonSchema` on types from `chrono`, enable it as a feature in the `schemars` dependency in your `Cargo.toml` like so: ```toml [dependencies] schemars = { version = "1.0", features = ["chrono04"] } ``` schemars-1.2.1/examples/custom_serialization.rs000064400000000000000000000030511046102023000200640ustar 00000000000000use schemars::{schema_for, JsonSchema, Schema, SchemaGenerator}; use serde::{Deserialize, Serialize}; // `int_as_string` and `bool_as_string` use the schema for `String`. #[derive(Default, Deserialize, Serialize, JsonSchema)] pub struct MyStruct { #[serde(default = "eight", with = "as_string")] #[schemars(with = "String")] pub int_as_string: i32, #[serde(default = "eight")] pub int_normal: i32, #[serde(default, with = "as_string")] #[schemars(schema_with = "make_custom_schema")] pub bool_as_string: bool, #[serde(default)] pub bool_normal: bool, } fn make_custom_schema(generator: &mut SchemaGenerator) -> Schema { let mut schema = String::json_schema(generator); schema.insert("format".into(), "boolean".into()); schema } fn eight() -> i32 { 8 } // This module serializes values as strings mod as_string { use serde::{de::Error, Deserialize, Deserializer, Serializer}; pub fn serialize(value: &T, serializer: S) -> Result where T: std::fmt::Display, S: Serializer, { serializer.collect_str(value) } pub fn deserialize<'de, T, D>(deserializer: D) -> Result where T: std::str::FromStr, D: Deserializer<'de>, { let string = String::deserialize(deserializer)?; string .parse() .map_err(|_| D::Error::custom("Input was not valid")) } } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/custom_serialization.schema.json000064400000000000000000000007431046102023000216550ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "bool_as_string": { "type": "string", "format": "boolean", "default": "false" }, "bool_normal": { "type": "boolean", "default": false }, "int_as_string": { "type": "string", "default": "8" }, "int_normal": { "type": "integer", "format": "int32", "default": 8 } } } schemars-1.2.1/examples/custom_settings.rs000064400000000000000000000011541046102023000170510ustar 00000000000000use schemars::{generate::SchemaSettings, JsonSchema}; #[derive(JsonSchema)] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(JsonSchema)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } fn main() { let settings = SchemaSettings::draft07().with(|s| { s.meta_schema = None; s.inline_subschemas = true; }); let generator = settings.into_generator(); let schema = generator.into_root_schema_for::(); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/custom_settings.schema.json000064400000000000000000000025661046102023000206450ustar 00000000000000{ "title": "MyStruct", "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer", "format": "int32" }, "my_nullable_enum": { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "StringNewType": { "type": "string" } }, "additionalProperties": false, "required": [ "StringNewType" ] }, { "type": "object", "properties": { "StructVariant": { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" } } }, "required": [ "floats" ] } }, "additionalProperties": false, "required": [ "StructVariant" ] } ] }, { "type": "null" } ] } }, "required": [ "my_int", "my_bool" ] } schemars-1.2.1/examples/doc_comments.rs000064400000000000000000000015171046102023000162740ustar 00000000000000use schemars::{schema_for, JsonSchema}; /// # My Amazing Struct /// This struct shows off generating a schema with /// a custom title and description. #[derive(JsonSchema)] pub struct MyStruct { /// # My Amazing Integer pub my_int: i32, /// This bool has a description, but no title. pub my_bool: bool, /// # A Nullable Enum /// This enum might be set, or it might not. pub my_nullable_enum: Option, } /// # My Amazing Enum #[derive(JsonSchema)] pub enum MyEnum { /// A wrapper around a `String` StringNewType(String), /// A struct-like enum variant which contains /// some floats StructVariant { /// The floats themselves floats: Vec, }, } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/doc_comments.schema.json000064400000000000000000000036051046102023000200600ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "My Amazing Struct", "description": "This struct shows off generating a schema with\na custom title and description.", "type": "object", "properties": { "my_bool": { "description": "This bool has a description, but no title.", "type": "boolean" }, "my_int": { "title": "My Amazing Integer", "type": "integer", "format": "int32" }, "my_nullable_enum": { "title": "A Nullable Enum", "description": "This enum might be set, or it might not.", "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ] } }, "required": [ "my_int", "my_bool" ], "$defs": { "MyEnum": { "title": "My Amazing Enum", "oneOf": [ { "description": "A wrapper around a `String`", "type": "object", "properties": { "StringNewType": { "type": "string" } }, "additionalProperties": false, "required": [ "StringNewType" ] }, { "description": "A struct-like enum variant which contains\nsome floats", "type": "object", "properties": { "StructVariant": { "type": "object", "properties": { "floats": { "description": "The floats themselves", "type": "array", "items": { "type": "number", "format": "float" } } }, "required": [ "floats" ] } }, "additionalProperties": false, "required": [ "StructVariant" ] } ] } } } schemars-1.2.1/examples/enum_repr.rs000064400000000000000000000004371046102023000156160ustar 00000000000000use schemars::{schema_for, JsonSchema_repr}; #[derive(JsonSchema_repr)] #[repr(u8)] enum SmallPrime { Two = 2, Three = 3, Five = 5, Seven = 7, } fn main() { let schema = schema_for!(SmallPrime); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/enum_repr.schema.json000064400000000000000000000002321046102023000173730ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "SmallPrime", "type": "integer", "enum": [ 2, 3, 5, 7 ] } schemars-1.2.1/examples/from_value.rs000064400000000000000000000010451046102023000157550ustar 00000000000000use schemars::schema_for_value; use serde::Serialize; #[derive(Serialize)] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(Serialize)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } fn main() { let schema = schema_for_value!(MyStruct { my_int: 123, my_bool: true, my_nullable_enum: Some(MyEnum::StringNewType("foo".to_string())) }); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/from_value.schema.json000064400000000000000000000006161046102023000175440ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer" }, "my_nullable_enum": true }, "examples": [ { "my_bool": true, "my_int": 123, "my_nullable_enum": { "StringNewType": "foo" } } ] } schemars-1.2.1/examples/main.rs000064400000000000000000000006261046102023000145460ustar 00000000000000use schemars::{schema_for, JsonSchema}; #[derive(JsonSchema)] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(JsonSchema)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/main.schema.json000064400000000000000000000025461046102023000163350ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer", "format": "int32" }, "my_nullable_enum": { "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ] } }, "required": [ "my_int", "my_bool" ], "$defs": { "MyEnum": { "oneOf": [ { "type": "object", "properties": { "StringNewType": { "type": "string" } }, "additionalProperties": false, "required": [ "StringNewType" ] }, { "type": "object", "properties": { "StructVariant": { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" } } }, "required": [ "floats" ] } }, "additionalProperties": false, "required": [ "StructVariant" ] } ] } } } schemars-1.2.1/examples/remote_derive.rs000064400000000000000000000024371046102023000164550ustar 00000000000000// Pretend that this is somebody else's crate, not a module. mod other_crate { // Neither Schemars nor the other crate provides a JsonSchema impl // for this struct. pub struct Duration { pub secs: i64, pub nanos: i32, } } //////////////////////////////////////////////////////////////////////////////// use other_crate::Duration; use schemars::{schema_for, JsonSchema}; // This is just a copy of the remote data structure that Schemars can use to // create a suitable JsonSchema impl. #[derive(JsonSchema)] #[serde(remote = "Duration")] pub struct DurationDef { pub secs: i64, pub nanos: i32, } // Now the remote type can be used almost like it had its own JsonSchema impl // all along. The `with` attribute gives the path to the definition for the // remote type. Note that the real type of the field is the remote type, not // the definition type. #[derive(JsonSchema)] pub struct Process { pub command_line: String, #[serde(with = "DurationDef")] pub wall_time: Duration, // Generic types must be explicitly specified with turbofix `::<>` syntax. #[serde(with = "Vec::")] pub durations: Vec, } fn main() { let schema = schema_for!(Process); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/remote_derive.schema.json000064400000000000000000000013571046102023000202410ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Process", "type": "object", "properties": { "command_line": { "type": "string" }, "durations": { "type": "array", "items": { "$ref": "#/$defs/Duration" } }, "wall_time": { "$ref": "#/$defs/Duration" } }, "required": [ "command_line", "wall_time", "durations" ], "$defs": { "Duration": { "type": "object", "properties": { "nanos": { "type": "integer", "format": "int32" }, "secs": { "type": "integer", "format": "int64" } }, "required": [ "secs", "nanos" ] } } } schemars-1.2.1/examples/schemars_attrs.rs000064400000000000000000000017611046102023000166450ustar 00000000000000use schemars::{schema_for, JsonSchema, Schema}; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, JsonSchema)] #[schemars(rename_all = "camelCase", deny_unknown_fields, extend("x-customProperty" = "example"))] pub struct MyStruct { #[serde(rename = "thisIsOverridden")] #[schemars(rename = "myNumber", range(min = 1, max = 10), transform = remove_format)] pub my_int: i32, pub my_bool: bool, #[schemars(default)] pub my_nullable_enum: Option, #[schemars(inner(regex(pattern = "^x$")))] pub my_vec_str: Vec, } #[derive(Deserialize, Serialize, JsonSchema)] #[schemars(untagged)] pub enum MyEnum { StringNewType(#[schemars(email)] String), StructVariant { #[schemars(length(min = 1, max = 100))] floats: Vec, }, } fn remove_format(schema: &mut Schema) { schema.remove("format"); } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/schemars_attrs.schema.json000064400000000000000000000023121046102023000204220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "myBool": { "type": "boolean" }, "myNullableEnum": { "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ], "default": null }, "myNumber": { "type": "integer", "maximum": 10, "minimum": 1 }, "myVecStr": { "type": "array", "items": { "type": "string", "pattern": "^x$" } } }, "additionalProperties": false, "required": [ "myNumber", "myBool", "myVecStr" ], "x-customProperty": "example", "$defs": { "MyEnum": { "anyOf": [ { "type": "string", "format": "email" }, { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" }, "maxItems": 100, "minItems": 1 } }, "required": [ "floats" ] } ] } } } schemars-1.2.1/examples/serde_attrs.rs000064400000000000000000000011561046102023000161400ustar 00000000000000use schemars::{schema_for, JsonSchema}; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct MyStruct { #[serde(rename = "myNumber")] pub my_int: i32, pub my_bool: bool, #[serde(default)] pub my_nullable_enum: Option, } #[derive(Deserialize, Serialize, JsonSchema)] #[serde(untagged)] pub enum MyEnum { StringNewType(String), StructVariant { floats: Vec }, } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/serde_attrs.schema.json000064400000000000000000000016641046102023000177300ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "myBool": { "type": "boolean" }, "myNullableEnum": { "anyOf": [ { "$ref": "#/$defs/MyEnum" }, { "type": "null" } ], "default": null }, "myNumber": { "type": "integer", "format": "int32" } }, "additionalProperties": false, "required": [ "myNumber", "myBool" ], "$defs": { "MyEnum": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" } } }, "required": [ "floats" ] } ] } } } schemars-1.2.1/examples/serialize_contract.rs000064400000000000000000000022421046102023000175020ustar 00000000000000use schemars::{generate::SchemaSettings, JsonSchema}; use serde::{Deserialize, Serialize}; #[derive(JsonSchema, Deserialize, Serialize)] // The schema effectively ignores this `rename_all`, since it doesn't apply to serialization #[serde(rename_all(deserialize = "PascalCase"))] pub struct MyStruct { pub my_int: i32, #[serde(skip_deserializing)] pub my_read_only_bool: bool, // This property is excluded from the schema #[serde(skip_serializing)] pub my_write_only_bool: bool, // This property is excluded from the "required" properties of the schema, because it may be // be skipped during serialization #[serde(skip_serializing_if = "str::is_empty")] pub maybe_string: String, pub definitely_string: String, } fn main() { // By default, generated schemas describe how types are deserialized. // So we modify the settings here to instead generate schemas describing how it's serialized: let settings = SchemaSettings::default().for_serialize(); let generator = settings.into_generator(); let schema = generator.into_root_schema_for::(); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/serialize_contract.schema.json000064400000000000000000000007641046102023000212750ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "definitely_string": { "type": "string" }, "maybe_string": { "type": "string" }, "my_int": { "type": "integer", "format": "int32" }, "my_read_only_bool": { "type": "boolean", "default": false, "readOnly": true } }, "required": [ "my_int", "my_read_only_bool", "definitely_string" ] } schemars-1.2.1/examples/validate.rs000064400000000000000000000010521046102023000154050ustar 00000000000000use schemars::{schema_for, JsonSchema}; #[derive(JsonSchema)] pub struct MyStruct { #[validate(range(min = 1, max = 10))] pub my_int: i32, pub my_bool: bool, #[validate(required)] pub my_nullable_enum: Option, } #[derive(JsonSchema)] pub enum MyEnum { StringNewType(#[validate(email)] String), StructVariant { #[validate(length(min = 1, max = 100))] floats: Vec, }, } fn main() { let schema = schema_for!(MyStruct); println!("{}", serde_json::to_string_pretty(&schema).unwrap()); } schemars-1.2.1/examples/validate.schema.json000064400000000000000000000025461046102023000172020ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "my_bool": { "type": "boolean" }, "my_int": { "type": "integer", "format": "int32", "maximum": 10, "minimum": 1 }, "my_nullable_enum": { "oneOf": [ { "type": "object", "properties": { "StringNewType": { "type": "string", "format": "email" } }, "additionalProperties": false, "required": [ "StringNewType" ] }, { "type": "object", "properties": { "StructVariant": { "type": "object", "properties": { "floats": { "type": "array", "items": { "type": "number", "format": "float" }, "maxItems": 100, "minItems": 1 } }, "required": [ "floats" ] } }, "additionalProperties": false, "required": [ "StructVariant" ] } ] } }, "required": [ "my_int", "my_bool", "my_nullable_enum" ] } schemars-1.2.1/src/_private/mod.rs000064400000000000000000000423751046102023000151720ustar 00000000000000use crate::_alloc_prelude::*; use crate::transform::{transform_immediate_subschemas, Transform}; use crate::{JsonSchema, Schema, SchemaGenerator}; use alloc::borrow::Cow; use serde::Serialize; use serde_json::{json, map::Entry, Map, Value}; mod regex_syntax; mod rustdoc; pub extern crate alloc; pub extern crate serde_json; pub use rustdoc::get_title_and_description; pub fn json_schema_for_internally_tagged_enum_newtype_variant( generator: &mut SchemaGenerator, ) -> Schema { let mut schema = T::json_schema(generator); // Inline the newtype's inner schema if any of: // - The type specifies that its schema should always be inlined // - The generator settings specify that all schemas should be inlined // - The inner type is a unit struct, which would cause an unsatisfiable schema due to mismatched `type`. // In this case, we replace its type with "object" in `apply_internal_enum_variant_tag` // - The inner schema specified `"additionalProperties": false` or `"unevaluatedProperties": false`, // since that would disallow the variant tag. If additional/unevaluatedProperties is in the top-level // schema, then we can leave it there, because it will "see" the variant tag property. But if it is // nested e.g. in an `allOf`, then it must be removed, which is why we run `AllowUnknownProperties` // but only on immediate subschemas. let mut transform = AllowUnknownProperties::default(); transform_immediate_subschemas(&mut transform, &mut schema); if T::inline_schema() || generator.settings().inline_subschemas || schema.get("type").and_then(Value::as_str) == Some("null") || schema.get("additionalProperties").and_then(Value::as_bool) == Some(false) || schema.get("unevaluatedProperties").and_then(Value::as_bool) == Some(false) || transform.did_modify { return schema; } // ...otherwise, we can freely refer to the schema via a `$ref` generator.subschema_for::() } // Helper for generating schemas for flattened enums and `Option` fields. pub fn json_schema_for_flatten( generator: &mut SchemaGenerator, required: bool, ) -> Schema { /// Non-generic inner function to reduce monomorphization overhead fn inner(mut schema: Schema, is_optional: bool) -> Schema { // Special handling for externally-tagged enums with unit variants. // Unit variants are normally serialized as strings, but when flattened, are serialized // as objects like `{ "VariantName": null }` if let Some(unit_variants) = remove_unit_variants(&mut schema) { if let Value::Array(one_of) = schema .ensure_object() .entry("oneOf") .or_insert(Value::Array(Vec::new())) { one_of.extend( unit_variants .iter() .filter_map(Value::as_str) .map(|variant| { json!({ "type": "object", "properties": { variant: { "type": "null" } }, "required": [variant], }) }), ); } } if is_optional { schema.remove("required"); // Handle `Option<>` of externally/internally/adjacently-tagged enums if let Some(one_of) = schema.remove("oneOf") { // We can't just add `{}` to the existing `oneOf`, because its items must be // mutually-exclusive, and `{}` matches everything. flatten( &mut schema, json_schema!({ "anyOf": [ { "oneOf": one_of }, {} ] }), ); } // Handle `Option<>` of untagged enums if let Some(Value::Array(any_of)) = schema.get_mut("anyOf") { let empty_object = Value::Object(Map::new()); if !any_of.contains(&empty_object) { any_of.push(empty_object); } } } // Always allow aditional/unevaluated properties, because the outer struct determines // whether it denies unknown fields. AllowUnknownProperties::default().transform(&mut schema); schema } fn remove_unit_variants(schema: &mut Schema) -> Option> { // For enums that only have unit variants, all variants are in `enum` if schema.get("type").and_then(Value::as_str) == Some("string") { // Remove both `"enum": [...]`... if let Some(Value::Array(a)) = schema.remove("enum") { // ...and `"type": "string"`, since the variants are not serialized as strings schema.remove("type"); return Some(a); } } // For enums that have unit and other variants, unit variants are in the first `oneOf` item let one_of = schema.get_mut("oneOf")?.as_array_mut()?; let first = <&mut Schema>::try_from(one_of.get_mut(0)?).ok()?; if first.get("type").and_then(Value::as_str) == Some("string") { if let Some(Value::Array(a)) = first.remove("enum") { one_of.remove(0); return Some(a); } } None } inner( T::_schemars_private_non_optional_json_schema(generator), T::_schemars_private_is_option() && !required, ) } #[derive(Default)] struct AllowUnknownProperties { did_modify: bool, } impl Transform for AllowUnknownProperties { fn transform(&mut self, schema: &mut Schema) { if schema.get("additionalProperties").and_then(Value::as_bool) == Some(false) { schema.remove("additionalProperties"); self.did_modify = true; } if schema.get("unevaluatedProperties").and_then(Value::as_bool) == Some(false) { schema.remove("unevaluatedProperties"); self.did_modify = true; } transform_immediate_subschemas(self, schema); } } /// Hack to simulate specialization: /// `MaybeSerializeWrapper(x).maybe_to_value()` will resolve to either /// - The inherent method `MaybeSerializeWrapper::maybe_to_value(...)` if x is `Serialize` /// - The trait method `NoSerialize::maybe_to_value(...)` from the blanket impl otherwise #[doc(hidden)] #[macro_export] macro_rules! _schemars_maybe_to_value { ($expression:expr) => {{ #[allow(unused_imports)] use $crate::_private::{MaybeSerializeWrapper, NoSerialize as _}; MaybeSerializeWrapper($expression).maybe_to_value() }}; } pub struct MaybeSerializeWrapper(pub T); pub trait NoSerialize: Sized { fn maybe_to_value(self) -> Option { None } } impl NoSerialize for T {} impl MaybeSerializeWrapper { pub fn maybe_to_value(self) -> Option { serde_json::value::to_value(self.0).ok() } } /// Create a schema for a unit enum variant #[must_use] pub fn new_unit_enum_variant(variant: &str) -> Schema { json_schema!({ "type": "string", "const": variant, }) } /// Hack to simulate specialization: /// `>::maybe_schema_id()` will resolve to either /// - The inherent method `MaybeJsonSchemaWrapper::maybe_schema_id()` if T impls `JsonSchema` /// - this returns `T::schema_id()` /// - The trait method `NoJsonSchema::maybe_schema_id()` from the blanket impl otherwise /// - this returns `core::any::type_name::()`` #[doc(hidden)] #[macro_export] macro_rules! _schemars_maybe_schema_id { ($ty:ty) => {{ #[allow(unused_imports)] use $crate::_private::{MaybeJsonSchemaWrapper, NoJsonSchema as _}; >::maybe_schema_id() }}; } pub struct MaybeJsonSchemaWrapper(core::marker::PhantomData); pub trait NoJsonSchema { #[must_use] fn maybe_schema_id() -> Cow<'static, str> { Cow::Borrowed(core::any::type_name::()) } } impl NoJsonSchema for T {} impl MaybeJsonSchemaWrapper { #[must_use] pub fn maybe_schema_id() -> Cow<'static, str> { T::schema_id() } } /// Create a schema for an externally tagged enum variant #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn new_externally_tagged_enum_variant(variant: &str, sub_schema: Schema) -> Schema { // TODO: this can be optimised by inserting the `sub_schema` as a `Value` rather than // using the `json_schema!` macro which borrows and serializes the sub_schema json_schema!({ "type": "object", "properties": { variant: sub_schema }, "required": [variant], "additionalProperties": false, }) } /// Update a schema for an internally tagged enum variant pub fn apply_internal_enum_variant_tag( schema: &mut Schema, tag_name: &str, variant: &str, deny_unknown_fields: bool, ) { let obj = schema.ensure_object(); let is_unit = obj.get("type").and_then(Value::as_str) == Some("null"); obj.insert("type".to_owned(), "object".into()); if let Some(properties) = obj .entry("properties") .or_insert(Value::Object(Map::new())) .as_object_mut() { properties.insert( tag_name.to_string(), json!({ "type": "string", "const": variant }), ); } if let Some(required) = obj .entry("required") .or_insert(Value::Array(Vec::new())) .as_array_mut() { required.insert(0, tag_name.into()); } if deny_unknown_fields && is_unit { obj.entry("additionalProperties").or_insert(false.into()); } } pub fn insert_object_property( schema: &mut Schema, key: &str, is_optional: bool, sub_schema: Schema, ) { let obj = schema.ensure_object(); if let Some(properties) = obj .entry("properties") .or_insert(Value::Object(Map::new())) .as_object_mut() { properties.insert(key.to_owned(), sub_schema.into()); } if !is_optional { if let Some(req) = obj .entry("required") .or_insert(Value::Array(Vec::new())) .as_array_mut() { req.push(key.into()); } } } pub fn insert_metadata_property_if_nonempty( schema: &mut Schema, key: &str, value: impl Into, ) { let value: String = value.into(); if !value.is_empty() { schema.insert(key.to_owned(), value.into()); } } pub fn insert_validation_property( schema: &mut Schema, required_type: &str, key: &str, value: impl Into, ) { if schema.has_type(required_type) || (required_type == "number" && schema.has_type("integer")) { schema.insert(key.to_owned(), value.into()); } } pub fn must_contain(schema: &mut Schema, substring: &str) { let escaped = regex_syntax::escape(substring); insert_validation_property(schema, "string", "pattern", escaped); } pub fn apply_inner_validation(schema: &mut Schema, f: fn(&mut Schema) -> ()) { if let Some(inner_schema) = schema.get_mut("items").and_then(|i| i.try_into().ok()) { f(inner_schema); } } pub fn flatten(schema: &mut Schema, other: Schema) { fn flatten_property(obj1: &mut Map, key: String, value2: Value) { match obj1.entry(key) { Entry::Vacant(vacant) => { vacant.insert(value2); } Entry::Occupied(occupied) => { match occupied.key().as_str() { "required" | "allOf" => { if let Value::Array(a1) = occupied.into_mut() { if let Value::Array(a2) = value2 { a1.extend(a2); } } } "properties" | "patternProperties" => { if let Value::Object(o1) = occupied.into_mut() { if let Value::Object(o2) = value2 { o1.extend(o2); } } } "oneOf" | "anyOf" => { let (key, current) = occupied.remove_entry(); flatten_property( obj1, "allOf".to_owned(), json!([ { &key: current }, { key: value2 } ]), ); } _ => { // leave the original value as it is (don't modify `schema`) } } } } } match other.try_to_object() { Err(false) => {} Err(true) => { if let Some(obj) = schema.as_object_mut() { if !obj.contains_key("additionalProperties") && !obj.contains_key("unevaluatedProperties") { let key = if contains_immediate_subschema(obj) { "unevaluatedProperties" } else { "additionalProperties" }; obj.insert(key.to_owned(), true.into()); } } } Ok(mut obj2) => { let obj1 = schema.ensure_object(); // For complex merges, replace `additionalProperties` with `unevaluatedProperties` // which usually "works out better". normalise_additional_unevaluated_properties(obj1, &obj2); normalise_additional_unevaluated_properties(&mut obj2, obj1); for (key, value2) in obj2 { flatten_property(obj1, key, value2); } } } } fn normalise_additional_unevaluated_properties( schema_obj1: &mut Map, schema_obj2: &Map, ) { if schema_obj1.contains_key("additionalProperties") && (schema_obj2.contains_key("unevaluatedProperties") || contains_immediate_subschema(schema_obj2)) { let ap = schema_obj1.remove("additionalProperties"); schema_obj1.insert("unevaluatedProperties".to_owned(), ap.into()); } } fn contains_immediate_subschema(schema_obj: &Map) -> bool { ["if", "allOf", "anyOf", "oneOf", "$ref"] .into_iter() .any(|k| schema_obj.contains_key(k)) } pub(crate) fn allow_null(generator: &mut SchemaGenerator, schema: &mut Schema) { fn is_null_schema(value: &Value) -> bool { <&Schema>::try_from(value).is_ok_and(|s| s.has_type("null")) } match schema.try_as_object_mut() { Ok(obj) => { if obj.len() == 1 && obj .get("anyOf") .and_then(Value::as_array) .is_some_and(|a| a.iter().any(is_null_schema)) { return; } if contains_immediate_subschema(obj) { *schema = json_schema!({ "anyOf": [ obj, <()>::json_schema(generator) ] }); // No need to check `type`/`const`/`enum` because they're trivially not present return; } if let Some(instance_type) = obj.get_mut("type") { match instance_type { Value::Array(array) => { let null = Value::from("null"); if !array.contains(&null) { array.push(null); } } Value::String(string) => { if string != "null" { let current_type = core::mem::take(string).into(); *instance_type = Value::Array(vec![current_type, "null".into()]); } } _ => {} } } if let Some(c) = obj.remove("const") { if !c.is_null() { obj.insert("enum".to_string(), Value::Array(vec![c, Value::Null])); } } else if let Some(Value::Array(e)) = obj.get_mut("enum") { if !e.contains(&Value::Null) { e.push(Value::Null); } } } Err(true) => {} Err(false) => { *schema = <()>::json_schema(generator); } } } #[cfg(test)] mod tests { use pretty_assertions::assert_eq; #[test] fn nested_option_schemas() { let mut option_schema = schema_for!(Option>); option_schema.remove("title"); let mut nested_option_schema = schema_for!(Option>>>); nested_option_schema.remove("title"); assert_eq!(option_schema, nested_option_schema); } } schemars-1.2.1/src/_private/regex_syntax.rs000064400000000000000000000036361046102023000171300ustar 00000000000000#![allow(clippy::all)] use crate::_alloc_prelude::*; // Copied from regex_syntax crate to avoid pulling in the whole crate just for a utility function // https://github.com/rust-lang/regex/blob/431c4e4867e1eb33eb39b23ed47c9934b2672f8f/regex-syntax/src/lib.rs // // Copyright (c) 2014 The Rust Project Developers // // Permission is hereby granted, free of charge, to any // person obtaining a copy of this software and associated // documentation files (the "Software"), to deal in the // Software without restriction, including without // limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice // shall be included in all copies or substantial portions // of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. pub fn escape(text: &str) -> String { let mut quoted = String::new(); escape_into(text, &mut quoted); quoted } fn escape_into(text: &str, buf: &mut String) { buf.reserve(text.len()); for c in text.chars() { if is_meta_character(c) { buf.push('\\'); } buf.push(c); } } fn is_meta_character(c: char) -> bool { match c { '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' => true, _ => false, } } schemars-1.2.1/src/_private/rustdoc.rs000064400000000000000000000041531046102023000160660ustar 00000000000000#[must_use] pub const fn get_title_and_description(doc: &str) -> (&str, &str) { let doc_bytes = trim_ascii(doc.as_bytes()); if !doc_bytes.is_empty() && doc_bytes[0] == b'#' { let title_end_index = match strchr(doc_bytes, b'\n') { Some(i) => i, None => doc_bytes.len(), }; let title = trim_ascii(trim_start(subslice(doc_bytes, 0, title_end_index), b'#')); let description = trim_ascii(subslice(doc_bytes, title_end_index, doc_bytes.len())); (to_utf8(title), to_utf8(description)) } else { ("", to_utf8(doc_bytes)) } } const fn strchr(bytes: &[u8], chr: u8) -> Option { let len = bytes.len(); let mut i = 0; while i < len { if bytes[i] == chr { return Some(i); } i += 1; } None } const fn subslice(mut bytes: &[u8], mut start: usize, end: usize) -> &[u8] { let mut trim_end_count = bytes.len() - end; if trim_end_count > 0 { while let [rest @ .., _last] = bytes { bytes = rest; trim_end_count -= 1; if trim_end_count == 0 { break; } } } if start > 0 { while let [_first, rest @ ..] = bytes { bytes = rest; start -= 1; if start == 0 { break; } } } bytes } const fn to_utf8(bytes: &[u8]) -> &str { match core::str::from_utf8(bytes) { Ok(x) => x, Err(_) => panic!("Invalid UTF-8"), } } const fn trim_start(mut bytes: &[u8], chr: u8) -> &[u8] { while let [first, rest @ ..] = bytes { if *first == chr { bytes = rest; } else { break; } } bytes } const fn trim_ascii(mut bytes: &[u8]) -> &[u8] { while let [first, rest @ ..] = bytes { if first.is_ascii_whitespace() { bytes = rest; } else { break; } } while let [rest @ .., last] = bytes { if last.is_ascii_whitespace() { bytes = rest; } else { break; } } bytes } schemars-1.2.1/src/consts.rs000064400000000000000000000025641046102023000141070ustar 00000000000000/*! Constants associated with JSON Schema generation. */ /// Known values of the `$schema` property. pub mod meta_schemas { /// The meta-schema for [JSON Schema Draft 7](https://json-schema.org/specification-links#draft-7) /// (`http://json-schema.org/draft-07/schema#`). pub const DRAFT07: &str = "http://json-schema.org/draft-07/schema#"; /// The meta-schema for [JSON Schema 2019-09](https://json-schema.org/specification-links#draft-2019-09-(formerly-known-as-draft-8)) /// (`https://json-schema.org/draft/2019-09/schema`). pub const DRAFT2019_09: &str = "https://json-schema.org/draft/2019-09/schema"; /// The meta-schema for [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12) /// (`https://json-schema.org/draft/2020-12/schema`). pub const DRAFT2020_12: &str = "https://json-schema.org/draft/2020-12/schema"; /// The meta-schema for [OpenAPI 3.0 schemas](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.4.md#schema) /// (`https://spec.openapis.org/oas/3.0/schema/2024-10-18#/definitions/Schema`). /// /// This should rarely be encountered in practice, as OpenAPI schemas are typically only /// embedded within OpenAPI documents, so do not have a `$schema` property set. pub const OPENAPI3: &str = "https://spec.openapis.org/oas/3.0/schema/2024-10-18#/definitions/Schema"; } schemars-1.2.1/src/encoding.rs000064400000000000000000000070741046102023000143650ustar 00000000000000use crate::_alloc_prelude::*; use alloc::borrow::Cow; use core::fmt::Write as _; /// Encodes a string for insertion into a JSON Pointer in URI fragment representation. #[must_use] pub fn encode_ref_name(name: &str) -> Cow<'_, str> { fn needs_encoding(byte: u8) -> bool { match byte { // `~` and `/` need encoding for JSON Pointer // See https://datatracker.ietf.org/doc/html/rfc6901#section-3 b'~' | b'/' => true, // These chars (and `~`) are valid in URL fragment // See https://datatracker.ietf.org/doc/html/rfc3986/#section-3.5 b'!' | b'$' | b'&'..=b';' | b'=' | b'?'..=b'Z' | b'_' | b'a'..=b'z' => false, // Everything else needs percent-encoding _ => true, } } if name.bytes().any(needs_encoding) { let mut buf = String::new(); for byte in name.bytes() { if byte == b'~' { buf.push_str("~0"); } else if byte == b'/' { buf.push_str("~1"); } else if needs_encoding(byte) { write!(buf, "%{byte:2X}").unwrap(); } else { buf.push(byte as char); } } Cow::Owned(buf) } else { Cow::Borrowed(name) } } /// Percent-decodes the given string, returning `None` if it results in invalid UTF-8. /// A `%` that is not followed by two hex digits is treated as a literal `%`. #[must_use] pub fn percent_decode(s: &str) -> Option> { if s.contains('%') { let mut buf = Vec::::new(); let mut segments = s.split('%'); buf.extend(segments.next().unwrap_or_default().as_bytes()); for segment in segments { if let Some(decoded_byte) = segment .get(0..2) .and_then(|p| u8::from_str_radix(p, 16).ok()) { buf.push(decoded_byte); buf.extend(&segment.as_bytes()[2..]); } else { buf.push(b'%'); buf.extend(segment.as_bytes()); } } String::from_utf8(buf).ok().map(Cow::Owned) } else { Some(Cow::Borrowed(s)) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_encode_ref_name() { assert_eq!(encode_ref_name("Simple!"), "Simple!"); assert_eq!( encode_ref_name("Needs %-encoding 🚀"), "Needs%20%25-encoding%20%F0%9F%9A%80" ); assert_eq!( encode_ref_name("aA0-._!$&'()*+,;=:@?"), "aA0-._!$&'()*+,;=:@?", ); assert_eq!(encode_ref_name("\"£%^\\~/"), "%22%C2%A3%25%5E%5C~0~1",); } #[test] fn test_percent_decode() { assert_eq!(percent_decode("Simple!"), Some("Simple!".into())); assert_eq!( percent_decode("Needs %-encoding 🚀"), Some("Needs %-encoding 🚀".into()) ); assert_eq!( percent_decode("Needs%20%25-encoding%20%F0%9F%9A%80"), Some("Needs %-encoding 🚀".into()) ); assert_eq!( percent_decode("aA0-._!$&'()*+,;=:@?"), Some("aA0-._!$&'()*+,;=:@?".into()) ); assert_eq!(percent_decode("\"£%^\\~/"), Some("\"£%^\\~/".into())); assert_eq!( percent_decode("%22%C2%A3%25%5E%5C~0~1"), Some("\"£%^\\~0~1".into()) ); assert_eq!(percent_decode("%%%2020%%%"), Some("%% 20%%%".into())); assert_eq!(percent_decode("%f0%9F%9a%80"), Some("🚀".into())); assert_eq!(percent_decode("%F0%9F%9A"), None); } } schemars-1.2.1/src/generate.rs000064400000000000000000000657121046102023000143740ustar 00000000000000/*! JSON Schema generator and settings. This module is useful if you want more control over how the schema generated than the [`schema_for!`] macro gives you. There are two main types in this module: * [`SchemaSettings`], which defines what JSON Schema features should be used when generating schemas (for example, how `Option`s should be represented). * [`SchemaGenerator`], which manages the generation of a schema document. */ use crate::consts::meta_schemas; use crate::Schema; use crate::_alloc_prelude::*; use crate::{transform::*, JsonSchema}; use alloc::collections::{BTreeMap, BTreeSet}; use core::{any::Any, fmt::Debug}; use dyn_clone::DynClone; use serde::Serialize; use serde_json::{Map as JsonMap, Value}; type CowStr = alloc::borrow::Cow<'static, str>; /// Settings to customize how Schemas are generated. /// /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// If you rely on generated schemas conforming to draft 2020-12, consider using the /// [`SchemaSettings::draft2020_12()`] method. #[derive(Debug, Clone)] #[non_exhaustive] #[allow(clippy::struct_excessive_bools)] pub struct SchemaSettings { /// A JSON pointer to the expected location of referenceable subschemas within the resulting /// root schema. /// /// A single leading `#` and/or single trailing `/` are ignored. /// /// Defaults to `"/$defs"`. pub definitions_path: CowStr, /// The URI of the meta-schema describing the structure of the generated schemas. /// /// Defaults to [`meta_schemas::DRAFT2020_12`] (`https://json-schema.org/draft/2020-12/schema`). pub meta_schema: Option, /// A list of [`Transform`]s that get applied to generated root schemas. /// /// Defaults to an empty vec (no transforms). pub transforms: Vec>, /// Inline all subschemas instead of using references. /// /// Some references may still be generated in schemas for recursive types. /// /// Defaults to `false`. pub inline_subschemas: bool, /// Whether the generated schemas should describe how types are serialized or *de*serialized. /// /// Defaults to `Contract::Deserialize`. pub contract: Contract, /// Whether to include enum variant names in their schema's `title` when using the [untagged /// enum representation](https://serde.rs/enum-representations.html#untagged). /// /// This setting is respected by `#[derive(JsonSchema)]` on enums, but manual implementations /// of `JsonSchema` may ignore this setting. /// /// Defaults to `false`. pub untagged_enum_variant_titles: bool, } impl Default for SchemaSettings { /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), /// but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// If you rely on generated schemas conforming to draft 2020-12, consider using [`SchemaSettings::draft2020_12()`] instead. fn default() -> SchemaSettings { SchemaSettings::draft2020_12() } } impl SchemaSettings { /// Creates `SchemaSettings` that conform to [JSON Schema Draft 7](https://json-schema.org/specification-links#draft-7). #[must_use] pub fn draft07() -> SchemaSettings { SchemaSettings { definitions_path: "/definitions".into(), meta_schema: Some(meta_schemas::DRAFT07.into()), transforms: vec![ Box::new(ReplaceUnevaluatedProperties), Box::new(RemoveRefSiblings), Box::new(ReplacePrefixItems), ], inline_subschemas: false, contract: Contract::Deserialize, untagged_enum_variant_titles: false, } } /// Creates `SchemaSettings` that conform to [JSON Schema 2019-09](https://json-schema.org/specification-links#draft-2019-09-(formerly-known-as-draft-8)). #[must_use] pub fn draft2019_09() -> SchemaSettings { SchemaSettings { definitions_path: "/$defs".into(), meta_schema: Some(meta_schemas::DRAFT2019_09.into()), transforms: vec![Box::new(ReplacePrefixItems)], inline_subschemas: false, contract: Contract::Deserialize, untagged_enum_variant_titles: false, } } /// Creates `SchemaSettings` that conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12). #[must_use] pub fn draft2020_12() -> SchemaSettings { SchemaSettings { definitions_path: "/$defs".into(), meta_schema: Some(meta_schemas::DRAFT2020_12.into()), transforms: Vec::new(), inline_subschemas: false, contract: Contract::Deserialize, untagged_enum_variant_titles: false, } } /// Creates `SchemaSettings` that conform to [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.4.md#schema). #[must_use] pub fn openapi3() -> SchemaSettings { SchemaSettings { definitions_path: "/components/schemas".into(), meta_schema: Some(meta_schemas::OPENAPI3.into()), transforms: vec![ Box::new(ReplaceUnevaluatedProperties), Box::new(ReplaceBoolSchemas { skip_additional_properties: true, }), Box::new(AddNullable::default()), Box::new(RemoveRefSiblings), Box::new(SetSingleExample), Box::new(ReplaceConstValue), Box::new(ReplacePrefixItems), ], inline_subschemas: false, contract: Contract::Deserialize, untagged_enum_variant_titles: false, } } /// Modifies the `SchemaSettings` by calling the given function. /// /// # Example /// ``` /// use schemars::generate::{SchemaGenerator, SchemaSettings}; /// /// let settings = SchemaSettings::default().with(|s| { /// s.meta_schema = None; /// s.inline_subschemas = true; /// }); /// let generator = settings.into_generator(); /// ``` #[must_use] pub fn with(mut self, configure_fn: impl FnOnce(&mut Self)) -> Self { configure_fn(&mut self); self } /// Appends the given transform to the list of [transforms](SchemaSettings::transforms) for /// these `SchemaSettings`. #[must_use] pub fn with_transform(mut self, transform: impl Transform + Clone + 'static + Send) -> Self { self.transforms.push(Box::new(transform)); self } /// Creates a new [`SchemaGenerator`] using these settings. #[must_use] pub fn into_generator(self) -> SchemaGenerator { SchemaGenerator::new(self) } /// Updates the settings to generate schemas describing how types are **deserialized**. #[must_use] pub fn for_deserialize(mut self) -> Self { self.contract = Contract::Deserialize; self } /// Updates the settings to generate schemas describing how types are **serialized**. #[must_use] pub fn for_serialize(mut self) -> Self { self.contract = Contract::Serialize; self } } /// A setting to specify whether generated schemas should describe how types are serialized or /// *de*serialized. /// /// This enum is marked as `#[non_exhaustive]` to reserve space to introduce further variants /// in future. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[allow(missing_docs)] #[non_exhaustive] pub enum Contract { Deserialize, Serialize, } impl Contract { /// Returns true if `self` is the `Deserialize` contract. #[must_use] pub fn is_deserialize(&self) -> bool { self == &Contract::Deserialize } /// Returns true if `self` is the `Serialize` contract. #[must_use] pub fn is_serialize(&self) -> bool { self == &Contract::Serialize } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] struct SchemaUid(CowStr, Contract); /// The main type used to generate JSON Schemas. /// /// # Example /// ``` /// use schemars::{JsonSchema, SchemaGenerator}; /// /// #[derive(JsonSchema)] /// struct MyStruct { /// foo: i32, /// } /// /// let generator = SchemaGenerator::default(); /// let schema = generator.into_root_schema_for::(); /// ``` #[derive(Debug)] pub struct SchemaGenerator { settings: SchemaSettings, definitions: JsonMap, pending_schema_ids: BTreeSet, schema_id_to_name: BTreeMap, used_schema_names: BTreeSet, // It's unlikely that `root_schema_id_stack` will ever contain more than one item, but it is // possible, e.g. if a `json_schema()` implementation calls `generator.root_schema_for<...>()` root_schema_id_stack: Vec, } impl Default for SchemaGenerator { fn default() -> Self { SchemaSettings::default().into_generator() } } impl Clone for SchemaGenerator { fn clone(&self) -> Self { Self { settings: self.settings.clone(), definitions: self.definitions.clone(), pending_schema_ids: BTreeSet::new(), schema_id_to_name: BTreeMap::new(), used_schema_names: BTreeSet::new(), root_schema_id_stack: Vec::new(), } } } impl From for SchemaGenerator { fn from(settings: SchemaSettings) -> Self { settings.into_generator() } } impl SchemaGenerator { /// Creates a new `SchemaGenerator` using the given settings. #[must_use] pub fn new(settings: SchemaSettings) -> SchemaGenerator { SchemaGenerator { settings, definitions: JsonMap::new(), pending_schema_ids: BTreeSet::new(), schema_id_to_name: BTreeMap::new(), used_schema_names: BTreeSet::new(), root_schema_id_stack: Vec::new(), } } /// Borrows the [`SchemaSettings`] being used by this `SchemaGenerator`. /// /// # Example /// ``` /// use schemars::SchemaGenerator; /// /// let generator = SchemaGenerator::default(); /// let settings = generator.settings(); /// /// assert_eq!(settings.inline_subschemas, false); /// ``` #[must_use] pub fn settings(&self) -> &SchemaSettings { &self.settings } /// Generates a JSON Schema for the type `T`, and returns either the schema itself or a `$ref` /// schema referencing `T`'s schema. /// /// If `T` is not [inlined](JsonSchema::inline_schema), this will add `T`'s schema to /// this generator's definitions, and return a `$ref` schema referencing that schema. /// Otherwise, this method behaves identically to [`JsonSchema::json_schema`]. /// /// If `T`'s schema depends on any [non-inlined](JsonSchema::inline_schema) schemas, then /// this method will add them to the `SchemaGenerator`'s schema definitions. pub fn subschema_for(&mut self) -> Schema { struct FindRef { schema: Schema, name_to_be_inserted: Option, } /// Non-generic inner function to improve compile times. fn find_ref( this: &mut SchemaGenerator, uid: &SchemaUid, inline_schema: bool, schema_name: fn() -> CowStr, ) -> Option { let return_ref = !inline_schema && (!this.settings.inline_subschemas || this.pending_schema_ids.contains(uid)); if !return_ref { return None; } if this.root_schema_id_stack.last() == Some(uid) { return Some(FindRef { schema: Schema::new_ref("#".to_owned()), name_to_be_inserted: None, }); } let name = this.schema_id_to_name.get(uid).cloned().unwrap_or_else(|| { let base_name = schema_name(); let mut name = CowStr::Borrowed(""); if this.used_schema_names.contains(base_name.as_ref()) { for i in 2.. { name = format!("{base_name}{i}").into(); if !this.used_schema_names.contains(&name) { break; } } } else { name = base_name; } this.used_schema_names.insert(name.clone()); this.schema_id_to_name.insert(uid.clone(), name.clone()); name }); let reference = format!( "#{}/{}", this.definitions_path_stripped(), crate::encoding::encode_ref_name(&name) ); Some(FindRef { schema: Schema::new_ref(reference), name_to_be_inserted: (!this.definitions().contains_key(name.as_ref())) .then_some(name), }) } let uid = self.schema_uid::(); let Some(FindRef { schema, name_to_be_inserted, }) = find_ref(self, &uid, T::inline_schema(), T::schema_name) else { return self.json_schema_internal::(&uid); }; if let Some(name) = name_to_be_inserted { self.insert_new_subschema_for::(name, &uid); } schema } fn insert_new_subschema_for(&mut self, name: CowStr, uid: &SchemaUid) { // TODO: If we've already added a schema for T with the "opposite" contract, then check // whether the new schema is identical. If so, re-use the original for both contracts. let dummy = false.into(); // insert into definitions BEFORE calling json_schema to avoid infinite recursion self.definitions.insert(name.clone().into(), dummy); let schema = self.json_schema_internal::(uid); self.definitions.insert(name.into(), schema.to_value()); } /// Borrows the collection of all [non-inlined](JsonSchema::inline_schema) schemas that /// have been generated. /// /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the /// values are the schemas themselves. #[must_use] pub fn definitions(&self) -> &JsonMap { &self.definitions } /// Mutably borrows the collection of all [non-inlined](JsonSchema::inline_schema) /// schemas that have been generated. /// /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the /// values are the schemas themselves. #[must_use] pub fn definitions_mut(&mut self) -> &mut JsonMap { &mut self.definitions } /// Returns the collection of all [non-inlined](JsonSchema::inline_schema) schemas that /// have been generated, leaving an empty `Map` in its place. /// /// The keys of the returned `Map` are the [schema names](JsonSchema::schema_name), and the /// values are the schemas themselves. /// /// To apply this generator's [transforms](SchemaSettings::transforms) to each of the returned /// schemas, set `apply_transforms` to `true`. pub fn take_definitions(&mut self, apply_transforms: bool) -> JsonMap { let mut definitions = core::mem::take(&mut self.definitions); if apply_transforms { for schema in definitions.values_mut().flat_map(<&mut Schema>::try_from) { self.apply_transforms(schema); } } definitions } /// Returns an iterator over the [transforms](SchemaSettings::transforms) being used by this /// `SchemaGenerator`. pub fn transforms_mut(&mut self) -> impl Iterator { self.settings.transforms.iter_mut().map(Box::as_mut) } /// Generates a JSON Schema for the type `T`. /// /// If `T`'s schema depends on any [non-inlined](JsonSchema::inline_schema) schemas, then /// this method will include them in the returned `Schema` at the [definitions /// path](SchemaSettings::definitions_path) (by default `"$defs"`). pub fn root_schema_for(&mut self) -> Schema { let schema_uid = self.schema_uid::(); self.root_schema_id_stack.push(schema_uid.clone()); let mut schema = self.json_schema_internal::(&schema_uid); let object = schema.ensure_object(); object .entry("title") .or_insert_with(|| T::schema_name().into()); if let Some(meta_schema) = self.settings.meta_schema.as_deref() { object.insert("$schema".into(), meta_schema.into()); } self.add_definitions(object, self.definitions.clone()); self.apply_transforms(&mut schema); self.root_schema_id_stack.pop(); schema } /// Consumes `self` and generates a JSON Schema for the type `T`. /// /// If `T`'s schema depends on any [non-inlined](JsonSchema::inline_schema) schemas, then /// this method will include them in the returned `Schema` at the [definitions /// path](SchemaSettings::definitions_path) (by default `"$defs"`). #[must_use] pub fn into_root_schema_for(mut self) -> Schema { let schema_uid = self.schema_uid::(); self.root_schema_id_stack.push(schema_uid.clone()); let mut schema = self.json_schema_internal::(&schema_uid); let object = schema.ensure_object(); object .entry("title") .or_insert_with(|| T::schema_name().into()); if let Some(meta_schema) = core::mem::take(&mut self.settings.meta_schema) { object.insert("$schema".into(), meta_schema.into()); } let definitions = self.take_definitions(false); self.add_definitions(object, definitions); self.apply_transforms(&mut schema); schema } /// Generates a JSON Schema for the given example value. /// /// If the value implements [`JsonSchema`], then prefer using the /// [`root_schema_for()`](Self::root_schema_for()) function which will generally produce a /// more precise schema, particularly when the value contains any enums. /// /// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`]. pub fn root_schema_for_value( &mut self, value: &T, ) -> Result { let mut schema = value.serialize(crate::ser::Serializer { generator: self, include_title: true, })?; let object = schema.ensure_object(); if let Ok(example) = serde_json::to_value(value) { object.insert("examples".into(), vec![example].into()); } if let Some(meta_schema) = self.settings.meta_schema.as_deref() { object.insert("$schema".into(), meta_schema.into()); } self.add_definitions(object, self.definitions.clone()); self.apply_transforms(&mut schema); Ok(schema) } /// Consumes `self` and generates a JSON Schema for the given example value. /// /// If the value implements [`JsonSchema`], then prefer using the /// [`into_root_schema_for()!`](Self::into_root_schema_for()) function which will generally /// produce a more precise schema, particularly when the value contains any enums. /// /// If the `Serialize` implementation of the value decides to fail, this will return an [`Err`]. pub fn into_root_schema_for_value( mut self, value: &T, ) -> Result { let mut schema = value.serialize(crate::ser::Serializer { generator: &mut self, include_title: true, })?; let object = schema.ensure_object(); if let Ok(example) = serde_json::to_value(value) { object.insert("examples".into(), vec![example].into()); } if let Some(meta_schema) = core::mem::take(&mut self.settings.meta_schema) { object.insert("$schema".into(), meta_schema.into()); } let definitions = self.take_definitions(false); self.add_definitions(object, definitions); self.apply_transforms(&mut schema); Ok(schema) } /// Returns a reference to the [contract](SchemaSettings::contract) for the settings on this /// `SchemaGenerator`. /// /// This specifies whether generated schemas describe serialize or *de*serialize behaviour. #[must_use] pub fn contract(&self) -> &Contract { &self.settings.contract } fn json_schema_internal(&mut self, uid: &SchemaUid) -> Schema { let did_add = self.pending_schema_ids.insert(uid.clone()); let schema = T::json_schema(self); if did_add { self.pending_schema_ids.remove(uid); } schema } fn add_definitions( &mut self, schema_object: &mut JsonMap, mut definitions: JsonMap, ) { if definitions.is_empty() { return; } let pointer = self.definitions_path_stripped(); let Some(target) = json_pointer_mut(schema_object, pointer, true) else { return; }; target.append(&mut definitions); } fn apply_transforms(&mut self, schema: &mut Schema) { for transform in self.transforms_mut() { transform.transform(schema); } } /// Returns `self.settings.definitions_path` as a plain JSON pointer to the definitions object, /// i.e. without a leading '#' or trailing '/' pub(crate) fn definitions_path_stripped(&self) -> &str { let path = &self.settings.definitions_path; let path = path.strip_prefix('#').unwrap_or(path); path.strip_suffix('/').unwrap_or(path) } fn schema_uid(&self) -> SchemaUid { SchemaUid(T::schema_id(), self.settings.contract.clone()) } } fn json_pointer_mut<'a>( mut object: &'a mut JsonMap, pointer: &str, create_if_missing: bool, ) -> Option<&'a mut JsonMap> { use serde_json::map::Entry; let pointer = pointer.strip_prefix('/')?; if pointer.is_empty() { return Some(object); } for mut segment in pointer.split('/') { let replaced: String; if segment.contains('~') { replaced = segment.replace("~1", "/").replace("~0", "~"); segment = &replaced; } let next_value = match object.entry(segment) { Entry::Occupied(o) => o.into_mut(), Entry::Vacant(v) if create_if_missing => v.insert(Value::Object(JsonMap::new())), Entry::Vacant(_) => return None, }; object = next_value.as_object_mut()?; } Some(object) } /// A [`Transform`] which implements additional traits required to be included in a /// [`SchemaSettings`]. /// /// You will rarely need to use this trait directly as it is automatically implemented for any type /// which implements all of: /// - [`Transform`] /// - [`std::any::Any`] (implemented for all `'static` types) /// - [`std::clone::Clone`] /// - [`std::marker::Send`] /// /// # Example /// ``` /// use schemars::transform::Transform; /// use schemars::generate::GenTransform; /// /// #[derive(Debug, Clone)] /// struct MyTransform; /// /// impl Transform for MyTransform { /// fn transform(&mut self, schema: &mut schemars::Schema) { /// todo!() /// } /// } /// /// let v: &dyn GenTransform = &MyTransform; /// assert!(v.is::()); /// ``` pub trait GenTransform: Transform + DynClone + Any + Send { #[deprecated = "Only to support pre-1.86 rustc"] #[doc(hidden)] fn _as_any(&self) -> &dyn Any; #[deprecated = "Only to support pre-1.86 rustc"] #[doc(hidden)] fn _as_any_mut(&mut self) -> &mut dyn Any; #[deprecated = "Only to support pre-1.86 rustc"] #[doc(hidden)] fn _into_any(self: Box) -> Box; } #[allow(deprecated, clippy::used_underscore_items)] impl dyn GenTransform { /// Returns `true` if the inner transform is of type `T`. #[must_use] pub fn is(&self) -> bool { self._as_any().is::() } /// Returns some reference to the inner transform if it is of type `T`, or /// `None` if it isn't. /// /// # Example /// To remove a specific transform from an instance of `SchemaSettings`: /// ``` /// use schemars::generate::SchemaSettings; /// use schemars::transform::ReplaceBoolSchemas; /// /// let mut settings = SchemaSettings::openapi3(); /// let original_len = settings.transforms.len(); /// /// settings.transforms.retain(|t| !t.is::()); /// /// assert_eq!(settings.transforms.len(), original_len - 1); /// ``` #[must_use] pub fn downcast_ref(&self) -> Option<&T> { self._as_any().downcast_ref::() } /// Returns some mutable reference to the inner transform if it is of type `T`, or /// `None` if it isn't. /// /// # Example /// To modify a specific transform in an instance of `SchemaSettings`: /// ``` /// use schemars::generate::SchemaSettings; /// use schemars::transform::ReplaceBoolSchemas; /// /// let mut settings = SchemaSettings::openapi3(); /// for t in &mut settings.transforms { /// if let Some(replace_bool_schemas) = t.downcast_mut::() { /// replace_bool_schemas.skip_additional_properties = false; /// } /// } /// ``` #[must_use] pub fn downcast_mut(&mut self) -> Option<&mut T> { self._as_any_mut().downcast_mut::() } /// Attempts to downcast the box to a concrete type. /// /// If the inner transform is not of type `T`, this returns `self` wrapped in an `Err` so that /// it can still be used. #[allow(clippy::missing_panics_doc)] // should never panic - `is()` ensures that downcast succeeds pub fn downcast( self: Box, ) -> Result, Box> { if self.is::() { Ok(self._into_any().downcast().unwrap()) } else { Err(self) } } } dyn_clone::clone_trait_object!(GenTransform); impl GenTransform for T where T: Transform + Clone + Any + Send, { fn _as_any(&self) -> &dyn Any { self } fn _as_any_mut(&mut self) -> &mut dyn Any { self } fn _into_any(self: Box) -> Box { self } } impl Debug for Box { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { #[allow(clippy::used_underscore_items)] self._debug_type_name(f) } } fn _assert_send() { fn assert() {} assert::(); assert::(); } schemars-1.2.1/src/json_schema_impls/array.rs000064400000000000000000000027421046102023000174070ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; // Does not require T: JsonSchema. impl JsonSchema for [T; 0] { inline_schema!(); fn schema_name() -> Cow<'static, str> { "EmptyArray".into() } fn schema_id() -> Cow<'static, str> { "[]".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "maxItems": 0, }) } } macro_rules! array_impls { ($($len:tt)+) => { $( impl JsonSchema for [T; $len] { inline_schema!(); fn schema_name() -> Cow<'static, str> { format!("Array_size_{}_of_{}", $len, T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("[{}; {}]", $len, T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "items": serde_json::Value::from(generator.subschema_for::()), "minItems": $len, "maxItems": $len, }) } } )+ } } array_impls! { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 } schemars-1.2.1/src/json_schema_impls/arrayvec07.rs000064400000000000000000000014521046102023000202510ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use arrayvec07::{ArrayString, ArrayVec}; // Do not set maxLength on the schema as that describes length in characters, but we only // know max length in bytes. forward_impl!(( JsonSchema for ArrayString) => String); impl JsonSchema for ArrayVec where T: JsonSchema, { inline_schema!(); fn schema_name() -> alloc::borrow::Cow<'static, str> { format!("Array_up_to_size_{}_of_{}", CAP, T::schema_name()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "items": generator.subschema_for::(), "maxItems": CAP }) } } schemars-1.2.1/src/json_schema_impls/atomic.rs000064400000000000000000000025541046102023000175460ustar 00000000000000use core::sync::atomic::*; #[cfg(target_has_atomic = "8")] forward_impl!(AtomicBool => bool); #[cfg(target_has_atomic = "8")] forward_impl!(AtomicI8 => i8); #[cfg(target_has_atomic = "16")] forward_impl!(AtomicI16 => i16); #[cfg(target_has_atomic = "32")] forward_impl!(AtomicI32 => i32); #[cfg(target_has_atomic = "64")] forward_impl!(AtomicI64 => i64); #[cfg(target_has_atomic = "ptr")] forward_impl!(AtomicIsize => isize); #[cfg(target_has_atomic = "8")] forward_impl!(AtomicU8 => u8); #[cfg(target_has_atomic = "16")] forward_impl!(AtomicU16 => u16); #[cfg(target_has_atomic = "32")] forward_impl!(AtomicU32 => u32); #[cfg(target_has_atomic = "64")] forward_impl!(AtomicU64 => u64); #[cfg(target_has_atomic = "ptr")] forward_impl!(AtomicUsize => usize); #[cfg(test)] mod tests { use super::*; use crate::schema_for; use pretty_assertions::assert_eq; #[test] fn schema_for_atomics() { let atomic_schema = schema_for!(( AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, )); let basic_schema = schema_for!((bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)); assert_eq!(atomic_schema, basic_schema); } } schemars-1.2.1/src/json_schema_impls/bytes1.rs000064400000000000000000000015271046102023000175000ustar 00000000000000use crate::_alloc_prelude::*; use crate::generate::Contract; use crate::{JsonSchema, Schema}; use alloc::borrow::Cow; use serde_json::Value; impl JsonSchema for bytes1::Bytes { fn schema_name() -> Cow<'static, str> { "Bytes".into() } fn schema_id() -> Cow<'static, str> { "bytes::Bytes".into() } fn json_schema(generator: &mut crate::SchemaGenerator) -> crate::Schema { let ty = match generator.contract() { Contract::Deserialize => Value::Array(vec!["array".into(), "string".into()]), Contract::Serialize => "array".into(), }; let mut result = Schema::default(); result.insert("type".to_owned(), ty); result.insert("items".to_owned(), generator.subschema_for::().into()); result } } forward_impl!(bytes1::BytesMut => bytes1::Bytes); schemars-1.2.1/src/json_schema_impls/chrono04.rs000064400000000000000000000043521046102023000177240ustar 00000000000000use crate::SchemaGenerator; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use chrono04::{prelude::*, TimeDelta}; impl JsonSchema for Weekday { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Weekday".into() } fn schema_id() -> Cow<'static, str> { "chrono::Weekday".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "enum": [ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", ] }) } } impl JsonSchema for TimeDelta { inline_schema!(); fn schema_name() -> Cow<'static, str> { "TimeDelta".into() } fn schema_id() -> Cow<'static, str> { "chrono::TimeDelta".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "prefixItems": [ { "type": "integer", "format": "int64" }, { "type": "integer", "minimum": 0, "exclusiveMaximum": 1_000_000_000 } ], "minItems": 2, "maxItems": 2 }) } } macro_rules! formatted_string_impl { ($ty:ident, $format:literal) => { formatted_string_impl!($ty, $format, JsonSchema for $ty); }; ($ty:ident, $format:literal, $($desc:tt)+) => { impl $($desc)+ { inline_schema!(); fn schema_name() -> Cow<'static, str> { stringify!($ty).into() } fn schema_id() -> Cow<'static, str> { stringify!(chrono::$ty).into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "format": $format }) } } }; } formatted_string_impl!(NaiveDate, "date"); formatted_string_impl!(NaiveDateTime, "partial-date-time"); formatted_string_impl!(NaiveTime, "partial-time"); formatted_string_impl!(DateTime, "date-time", JsonSchema for DateTime); schemars-1.2.1/src/json_schema_impls/core.rs000064400000000000000000000071441046102023000172220ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::_private::allow_null; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use core::ops::{Bound, Range, RangeInclusive}; impl JsonSchema for Option { inline_schema!(); fn schema_name() -> Cow<'static, str> { format!("Nullable_{}", T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("Option<{}>", T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let mut schema = generator.subschema_for::(); allow_null(generator, &mut schema); schema } fn _schemars_private_non_optional_json_schema(generator: &mut SchemaGenerator) -> Schema { T::_schemars_private_non_optional_json_schema(generator) } fn _schemars_private_is_option() -> bool { true } } impl JsonSchema for Result { fn schema_name() -> Cow<'static, str> { format!("Result_of_{}_or_{}", T::schema_name(), E::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("Result<{}, {}>", T::schema_id(), E::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "oneOf": [ { "type": "object", "properties": { "Ok": generator.subschema_for::() }, "required": ["Ok"] }, { "type": "object", "properties": { "Err": generator.subschema_for::() }, "required": ["Err"] } ] }) } } impl JsonSchema for Bound { fn schema_name() -> Cow<'static, str> { format!("Bound_of_{}", T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("Bound<{}>", T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "oneOf": [ { "type": "object", "properties": { "Included": generator.subschema_for::() }, "required": ["Included"] }, { "type": "object", "properties": { "Excluded": generator.subschema_for::() }, "required": ["Excluded"] }, { "type": "string", "const": "Unbounded" } ] }) } } impl JsonSchema for Range { fn schema_name() -> Cow<'static, str> { format!("Range_of_{}", T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("Range<{}>", T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let subschema = generator.subschema_for::(); json_schema!({ "type": "object", "properties": { "start": subschema, "end": subschema }, "required": ["start", "end"] }) } } forward_impl!(( JsonSchema for RangeInclusive) => Range); forward_impl!(( JsonSchema for core::marker::PhantomData) => ()); forward_impl!((<'a> JsonSchema for core::fmt::Arguments<'a>) => String); schemars-1.2.1/src/json_schema_impls/decimal.rs000064400000000000000000000022611046102023000176630ustar 00000000000000use crate::_alloc_prelude::*; use crate::generate::Contract; use crate::{JsonSchema, Schema, SchemaGenerator}; use alloc::borrow::Cow; use serde_json::Value; macro_rules! decimal_impl { ($type:ty) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Decimal".into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let (ty, pattern) = match generator.contract() { Contract::Deserialize => ( Value::Array(vec!["string".into(), "number".into()]), r"^-?\d+(\.\d+)?([eE]\d+)?$".into(), ), Contract::Serialize => ("string".into(), r"^-?\d+(\.\d+)?$".into()), }; let mut result = Schema::default(); result.insert("type".to_owned(), ty); result.insert("pattern".to_owned(), pattern); result } } }; } #[cfg(feature = "rust_decimal1")] decimal_impl!(rust_decimal1::Decimal); #[cfg(feature = "bigdecimal04")] decimal_impl!(bigdecimal04::BigDecimal); schemars-1.2.1/src/json_schema_impls/either1.rs000064400000000000000000000022431046102023000176260ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use either1::Either; impl JsonSchema for Either { inline_schema!(); fn schema_name() -> Cow<'static, str> { format!("Either_{}_or_{}", L::schema_name(), R::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("either::Either<{}, {}>", L::schema_id(), R::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "oneOf": [ { "type": "object", "properties": { "Left": generator.subschema_for::() }, "additionalProperties": false, "required": [ "Left" ] }, { "type": "object", "properties": { "Right": generator.subschema_for::() }, "additionalProperties": false, "required": [ "Right" ] } ] }) } } schemars-1.2.1/src/json_schema_impls/ffi.rs000064400000000000000000000032461046102023000170350ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use serde_json::json; use std::ffi::{CStr, CString, OsStr, OsString}; impl JsonSchema for OsString { fn schema_name() -> Cow<'static, str> { "OsString".into() } fn schema_id() -> Cow<'static, str> { "std::ffi::OsString".into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "oneOf": [ { "type": "object", "properties": { "Unix": >::json_schema(generator) }, "required": ["Unix"] }, { "type": "object", "properties": { "Windows": >::json_schema(generator) }, "required": ["Windows"] }, ] }) } } forward_impl!(OsStr => OsString); impl JsonSchema for CString { fn schema_name() -> Cow<'static, str> { "CString".into() } fn schema_id() -> Cow<'static, str> { "std::ffi::CString".into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let ty = if generator.contract().is_deserialize() { json!(["array", "string"]) } else { json!("array") }; json_schema!({ "type": ty, "items": { "type": "integer", "minimum": 1, "maximum": 255 }, }) } } forward_impl!(CStr => CString); schemars-1.2.1/src/json_schema_impls/indexmap2.rs000064400000000000000000000004441046102023000201550ustar 00000000000000use crate::JsonSchema; use alloc::collections::{BTreeMap, BTreeSet}; use indexmap2::{IndexMap, IndexSet}; forward_impl!(( JsonSchema for IndexMap) => BTreeMap); forward_impl!(( JsonSchema for IndexSet) => BTreeSet); schemars-1.2.1/src/json_schema_impls/jiff02.rs000064400000000000000000000022751046102023000173520ustar 00000000000000use crate::{json_schema, JsonSchema, Schema, SchemaGenerator}; use alloc::borrow::Cow; use jiff02::civil::{Date, DateTime, Time}; use jiff02::{SignedDuration, Span, Timestamp, Zoned}; macro_rules! formatted_string_impl { ($ty:ident, $format:literal) => { formatted_string_impl!($ty, $format, JsonSchema for $ty); }; ($ty:ident, $format:literal, $($desc:tt)+) => { impl $($desc)+ { inline_schema!(); fn schema_name() -> Cow<'static, str> { stringify!($ty).into() } fn schema_id() -> Cow<'static, str> { stringify!(jiff::$ty).into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "format": $format }) } } }; } formatted_string_impl!(SignedDuration, "duration"); formatted_string_impl!(Span, "duration"); formatted_string_impl!(Timestamp, "date-time"); formatted_string_impl!(Zoned, "zoned-date-time"); formatted_string_impl!(Date, "date"); formatted_string_impl!(Time, "partial-time"); formatted_string_impl!(DateTime, "partial-date-time"); schemars-1.2.1/src/json_schema_impls/maps.rs000064400000000000000000000115441046102023000172310ustar 00000000000000use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema, SchemaGenerator}; use alloc::borrow::Cow; use alloc::collections::{BTreeMap, BTreeSet}; use serde_json::{Map, Value}; #[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)] enum IntegerSupport { None, Unsigned, Signed, } impl JsonSchema for BTreeMap where K: JsonSchema, V: JsonSchema, { inline_schema!(); fn schema_name() -> Cow<'static, str> { Cow::Owned(if K::schema_id() == ::schema_id() { format!("Map_of_{}", V::schema_name()) } else { format!("Map_from_{}_to_{}", K::schema_name(), V::schema_name()) }) } fn schema_id() -> Cow<'static, str> { Cow::Owned(if K::schema_id() == ::schema_id() { format!("Map<{}>", V::schema_id()) } else { format!("Map<{}, {}>", K::schema_id(), V::schema_id()) }) } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let key_schema = K::json_schema(generator); let value_schema = generator.subschema_for::(); let mut map_schema = json_schema!({ "type": "object", }); let Some(mut options) = key_schema .get("anyOf") .and_then(Value::as_array) .and_then(|a| a.iter().map(Value::as_object).collect::>>()) .or_else(|| Some(vec![key_schema.as_object()?])) else { return json_schema!({ "additionalProperties": value_schema, "type": "object", }); }; // Handle refs let prefix = format!("#{}/", generator.definitions_path_stripped()); for option in &mut options { if let Some(d) = option .get("$ref") .and_then(Value::as_str) .and_then(|r| r.strip_prefix(&prefix)) .and_then(|r| generator.definitions().get(r)) .and_then(Value::as_object) { *option = d; } } let mut additional_properties = false; let mut support_integers = IntegerSupport::None; let mut patterns = BTreeSet::new(); let mut properties = BTreeSet::new(); for option in options { let key_pattern = option.get("pattern").and_then(Value::as_str); let key_enum = option .get("enum") .and_then(Value::as_array) .and_then(|a| a.iter().map(Value::as_str).collect::>>()); let key_type = option.get("type").and_then(Value::as_str); let key_minimum = option.get("minimum").and_then(Value::as_u64); match (key_pattern, key_enum, key_type) { (Some(pattern), _, Some("string")) => { patterns.insert(pattern); } (None, Some(enum_values), Some("string")) => { for value in enum_values { properties.insert(value); } } (_, _, Some("integer")) if key_minimum == Some(0) => { support_integers = support_integers.max(IntegerSupport::Unsigned); } (_, _, Some("integer")) => { support_integers = support_integers.max(IntegerSupport::Signed); } _ => { additional_properties = true; } } } if additional_properties { map_schema.insert( "additionalProperties".to_owned(), value_schema.clone().to_value(), ); } else { map_schema.insert("additionalProperties".to_owned(), Value::Bool(false)); } match support_integers { IntegerSupport::None => {} IntegerSupport::Unsigned => { patterns.insert(r"^\d+$"); } IntegerSupport::Signed => { patterns.insert(r"^-?\d+$"); } } if !patterns.is_empty() { let mut patterns_map = Map::new(); for pattern in patterns { patterns_map.insert(pattern.to_owned(), value_schema.clone().to_value()); } map_schema.insert("patternProperties".to_owned(), Value::Object(patterns_map)); } if !properties.is_empty() { let mut properties_map = Map::new(); for property in properties { properties_map.insert(property.to_owned(), value_schema.clone().to_value()); } map_schema.insert("properties".to_owned(), Value::Object(properties_map)); } map_schema } } #[cfg(feature = "std")] forward_impl!(( JsonSchema for std::collections::HashMap) => BTreeMap); schemars-1.2.1/src/json_schema_impls/mod.rs000064400000000000000000000045431046102023000170510ustar 00000000000000macro_rules! inline_schema { () => { fn inline_schema() -> bool { true } }; } macro_rules! forward_impl { (($($impl:tt)+) => $target:ty) => { impl $($impl)+ { fn inline_schema() -> bool { <$target as $crate::JsonSchema>::inline_schema() } fn schema_name() -> alloc::borrow::Cow<'static, str> { <$target as $crate::JsonSchema>::schema_name() } fn schema_id() -> alloc::borrow::Cow<'static, str> { <$target as $crate::JsonSchema>::schema_id() } fn json_schema(generator: &mut $crate::SchemaGenerator) -> $crate::Schema { <$target as $crate::JsonSchema>::json_schema(generator) } fn _schemars_private_non_optional_json_schema(generator: &mut $crate::SchemaGenerator) -> $crate::Schema { #[allow(clippy::used_underscore_items)] <$target as $crate::JsonSchema>::_schemars_private_non_optional_json_schema(generator) } fn _schemars_private_is_option() -> bool { #[allow(clippy::used_underscore_items)] <$target as $crate::JsonSchema>::_schemars_private_is_option() } } }; ($ty:ty => $target:ty) => { forward_impl!(($crate::JsonSchema for $ty) => $target); }; } mod array; mod core; mod maps; mod nonzero; mod primitives; mod sequences; mod serdejson; mod std_time; mod tuple; mod wrapper; mod atomic; #[cfg(feature = "std")] mod ffi; #[cfg(feature = "arrayvec07")] mod arrayvec07; #[cfg(feature = "bytes1")] mod bytes1; #[cfg(feature = "chrono04")] mod chrono04; #[cfg(any(feature = "rust_decimal1", feature = "bigdecimal04"))] mod decimal; #[cfg(feature = "either1")] mod either1; #[cfg(feature = "indexmap2")] mod indexmap2; #[cfg(feature = "jiff02")] mod jiff02; #[cfg(feature = "semver1")] mod semver1; #[cfg(feature = "smallvec1")] forward_impl!(( crate::JsonSchema for smallvec1::SmallVec where A::Item: crate::JsonSchema) => alloc::vec::Vec); #[cfg(feature = "smol_str02")] forward_impl!(smol_str02::SmolStr => alloc::string::String); #[cfg(feature = "smol_str03")] forward_impl!(smol_str03::SmolStr => alloc::string::String); #[cfg(feature = "url2")] mod url2; #[cfg(feature = "uuid1")] mod uuid1; schemars-1.2.1/src/json_schema_impls/nonzero.rs000064400000000000000000000036331046102023000177630ustar 00000000000000use crate::_alloc_prelude::*; use crate::{JsonSchema, Schema, SchemaGenerator}; use alloc::borrow::Cow; use core::num::*; macro_rules! nonzero_signed_impl { ($type:ty => $primitive:ty) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { stringify!($type).into() } fn schema_id() -> Cow<'static, str> { stringify!(std::num::$type).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let mut schema = <$primitive>::json_schema(generator); schema.insert("not".to_owned(), serde_json::json!({ "const": 0 })); schema } } }; } nonzero_signed_impl!(NonZeroI8 => i8); nonzero_signed_impl!(NonZeroI16 => i16); nonzero_signed_impl!(NonZeroI32 => i32); nonzero_signed_impl!(NonZeroI64 => i64); nonzero_signed_impl!(NonZeroI128 => i128); nonzero_signed_impl!(NonZeroIsize => isize); macro_rules! nonzero_unsigned_impl { ($type:ty => $primitive:ty) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { stringify!($type).into() } fn schema_id() -> Cow<'static, str> { stringify!(std::num::$type).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { let mut schema = <$primitive>::json_schema(generator); schema.insert("minimum".to_owned(), 1.into()); schema } } }; } nonzero_unsigned_impl!(NonZeroU8 => u8); nonzero_unsigned_impl!(NonZeroU16 => u16); nonzero_unsigned_impl!(NonZeroU32 => u32); nonzero_unsigned_impl!(NonZeroU64 => u64); nonzero_unsigned_impl!(NonZeroU128 => u128); nonzero_unsigned_impl!(NonZeroUsize => usize); schemars-1.2.1/src/json_schema_impls/primitives.rs000064400000000000000000000072431046102023000204650ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; macro_rules! simple_impl { ($type:ty => $instance_type:literal) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { $instance_type.into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": $instance_type }) } } }; ($type:ty => $instance_type:literal, $format:literal) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { $format.into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": $instance_type, "format": $format }) } } }; } macro_rules! ranged_impl { ($type:ty => $instance_type:literal, $format:literal) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { $format.into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": $instance_type, "format": $format, "minimum": <$type>::MIN, "maximum": <$type>::MAX }) } } }; } simple_impl!(str => "string"); simple_impl!(String => "string"); simple_impl!(bool => "boolean"); simple_impl!(f32 => "number", "float"); simple_impl!(f64 => "number", "double"); ranged_impl!(i8 => "integer", "int8"); ranged_impl!(i16 => "integer", "int16"); simple_impl!(i32 => "integer", "int32"); simple_impl!(i64 => "integer", "int64"); simple_impl!(i128 => "integer", "int128"); simple_impl!(isize => "integer", "int"); simple_impl!(() => "null"); #[cfg(feature = "std")] mod std_types { use super::*; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::{Path, PathBuf}; simple_impl!(Path => "string"); simple_impl!(PathBuf => "string"); simple_impl!(Ipv4Addr => "string", "ipv4"); simple_impl!(Ipv6Addr => "string", "ipv6"); simple_impl!(IpAddr => "string", "ip"); simple_impl!(SocketAddr => "string"); simple_impl!(SocketAddrV4 => "string"); simple_impl!(SocketAddrV6 => "string"); } macro_rules! unsigned_impl { ($type:ty => $instance_type:literal, $format:literal) => { impl JsonSchema for $type { inline_schema!(); fn schema_name() -> Cow<'static, str> { $format.into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": $instance_type, "format": $format, "minimum": 0 }) } } }; } ranged_impl!(u8 => "integer", "uint8"); ranged_impl!(u16 => "integer", "uint16"); unsigned_impl!(u32 => "integer", "uint32"); unsigned_impl!(u64 => "integer", "uint64"); unsigned_impl!(u128 => "integer", "uint128"); unsigned_impl!(usize => "integer", "uint"); impl JsonSchema for char { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Character".into() } fn schema_id() -> Cow<'static, str> { "char".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "minLength": 1, "maxLength": 1, }) } } schemars-1.2.1/src/json_schema_impls/semver1.rs000064400000000000000000000013541046102023000176510ustar 00000000000000use crate::SchemaGenerator; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use semver1::Version; impl JsonSchema for Version { fn schema_name() -> Cow<'static, str> { "SemVer".into() } fn schema_id() -> Cow<'static, str> { "semver::Version".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string "pattern": r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" }) } } schemars-1.2.1/src/json_schema_impls/sequences.rs000064400000000000000000000036001046102023000202560ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; macro_rules! seq_impl { ($($desc:tt)+) => { impl $($desc)+ where T: JsonSchema, { inline_schema!(); fn schema_name() -> Cow<'static, str> { format!("Array_of_{}", T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("[{}]", T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "items": generator.subschema_for::(), }) } } }; } macro_rules! set_impl { ($($desc:tt)+) => { impl $($desc)+ where T: JsonSchema, { inline_schema!(); fn schema_name() -> Cow<'static, str> { format!("Set_of_{}", T::schema_name()).into() } fn schema_id() -> Cow<'static, str> { format!("Set<{}>", T::schema_id()).into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "uniqueItems": true, "items": generator.subschema_for::(), }) } } }; } seq_impl!( JsonSchema for alloc::collections::BinaryHeap); seq_impl!( JsonSchema for alloc::collections::LinkedList); seq_impl!( JsonSchema for [T]); seq_impl!( JsonSchema for alloc::vec::Vec); seq_impl!( JsonSchema for alloc::collections::VecDeque); set_impl!( JsonSchema for alloc::collections::BTreeSet); #[cfg(feature = "std")] set_impl!( JsonSchema for std::collections::HashSet); schemars-1.2.1/src/json_schema_impls/serdejson.rs000064400000000000000000000014571046102023000202670ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use alloc::collections::BTreeMap; use serde_json::{Map, Number, Value}; impl JsonSchema for Value { inline_schema!(); fn schema_name() -> Cow<'static, str> { "AnyValue".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { true.into() } } forward_impl!(Map => BTreeMap); impl JsonSchema for Number { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Number".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "number" }) } } #[cfg(feature = "raw_value")] forward_impl!(serde_json::value::RawValue => Value); schemars-1.2.1/src/json_schema_impls/std_time.rs000064400000000000000000000023351046102023000200770ustar 00000000000000use crate::SchemaGenerator; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; impl JsonSchema for core::time::Duration { fn schema_name() -> Cow<'static, str> { "Duration".into() } fn schema_id() -> Cow<'static, str> { "std::time::Duration".into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "object", "required": ["secs", "nanos"], "properties": { "secs": u64::json_schema(generator), "nanos": u32::json_schema(generator), } }) } } #[cfg(feature = "std")] impl JsonSchema for std::time::SystemTime { fn schema_name() -> Cow<'static, str> { "SystemTime".into() } fn schema_id() -> Cow<'static, str> { "std::time::SystemTime".into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "object", "required": ["secs_since_epoch", "nanos_since_epoch"], "properties": { "secs_since_epoch": u64::json_schema(generator), "nanos_since_epoch": u32::json_schema(generator), } }) } } schemars-1.2.1/src/json_schema_impls/tuple.rs000064400000000000000000000035521046102023000174220ustar 00000000000000use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; macro_rules! tuple_impls { ($($len:expr => ($($name:ident)+))+) => { $( impl<$($name: JsonSchema),+> JsonSchema for ($($name,)+) { inline_schema!(); fn schema_name() -> Cow<'static, str> { let mut name = "Tuple_of_".to_owned(); name.push_str(&[$($name::schema_name()),+].join("_and_")); name.into() } fn schema_id() -> Cow<'static, str> { let mut id = "(".to_owned(); id.push_str(&[$($name::schema_id()),+].join(",")); id.push(')'); id.into() } fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "array", "prefixItems": [ $(generator.subschema_for::<$name>()),+ ], "minItems": $len, "maxItems": $len, }) } } )+ } } tuple_impls! { 1 => (T0) 2 => (T0 T1) 3 => (T0 T1 T2) 4 => (T0 T1 T2 T3) 5 => (T0 T1 T2 T3 T4) 6 => (T0 T1 T2 T3 T4 T5) 7 => (T0 T1 T2 T3 T4 T5 T6) 8 => (T0 T1 T2 T3 T4 T5 T6 T7) 9 => (T0 T1 T2 T3 T4 T5 T6 T7 T8) 10 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9) 11 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10) 12 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11) 13 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12) 14 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13) 15 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14) 16 => (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15) } schemars-1.2.1/src/json_schema_impls/url2.rs000064400000000000000000000007231046102023000171520ustar 00000000000000use crate::SchemaGenerator; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use url2::Url; impl JsonSchema for Url { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Url".into() } fn schema_id() -> Cow<'static, str> { "url::Url".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "format": "uri", }) } } schemars-1.2.1/src/json_schema_impls/uuid1.rs000064400000000000000000000007321046102023000173150ustar 00000000000000use crate::SchemaGenerator; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; use uuid1::Uuid; impl JsonSchema for Uuid { inline_schema!(); fn schema_name() -> Cow<'static, str> { "Uuid".into() } fn schema_id() -> Cow<'static, str> { "uuid::Uuid".into() } fn json_schema(_: &mut SchemaGenerator) -> Schema { json_schema!({ "type": "string", "format": "uuid", }) } } schemars-1.2.1/src/json_schema_impls/wrapper.rs000064400000000000000000000021001046102023000177350ustar 00000000000000use crate::JsonSchema; use crate::_alloc_prelude::*; macro_rules! wrapper_impl { ($($desc:tt)+) => { forward_impl!(($($desc)+ where T: JsonSchema) => T); }; } wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a T); wrapper_impl!(<'a, T: ?Sized> JsonSchema for &'a mut T); wrapper_impl!( JsonSchema for Box); wrapper_impl!( JsonSchema for alloc::rc::Rc); wrapper_impl!( JsonSchema for alloc::rc::Weak); wrapper_impl!( JsonSchema for alloc::sync::Arc); wrapper_impl!( JsonSchema for alloc::sync::Weak); #[cfg(feature = "std")] wrapper_impl!( JsonSchema for std::sync::Mutex); #[cfg(feature = "std")] wrapper_impl!( JsonSchema for std::sync::RwLock); wrapper_impl!( JsonSchema for core::cell::Cell); wrapper_impl!( JsonSchema for core::cell::RefCell); wrapper_impl!(<'a, T: ?Sized + ToOwned> JsonSchema for alloc::borrow::Cow<'a, T>); wrapper_impl!( JsonSchema for core::num::Wrapping); wrapper_impl!( JsonSchema for core::cmp::Reverse); schemars-1.2.1/src/lib.rs000064400000000000000000000135551046102023000133460ustar 00000000000000#![forbid(unsafe_code)] #![deny( missing_docs, unused_imports, clippy::cargo, clippy::pedantic, clippy::exhaustive_structs, clippy::exhaustive_enums )] #![allow(clippy::wildcard_imports, clippy::missing_errors_doc)] #![doc = include_str!("../README.md")] #![no_std] extern crate alloc; #[cfg(feature = "std")] extern crate std; mod encoding; mod json_schema_impls; mod schema; mod ser; #[macro_use] mod macros; /// This module is only public for use by `schemars_derive`. It should not need to be used by code /// outside of `schemars`, and should not be considered part of the public API. #[doc(hidden)] #[allow(clippy::exhaustive_structs)] pub mod _private; pub mod consts; pub mod generate; pub mod transform; #[cfg(feature = "schemars_derive")] extern crate schemars_derive; use alloc::borrow::Cow; #[cfg(feature = "schemars_derive")] pub use schemars_derive::*; #[doc(inline)] pub use generate::SchemaGenerator; pub use schema::Schema; mod _alloc_prelude { pub use alloc::borrow::ToOwned; pub use alloc::boxed::Box; pub use alloc::format; pub use alloc::string::{String, ToString}; pub use alloc::vec; pub use alloc::vec::Vec; } /// A type which can be described as a JSON Schema document. /// /// This is implemented for many Rust primitive and standard library types. /// /// This can also be automatically derived on most custom types with `#[derive(JsonSchema)]` by /// enabling the `derive` feature flag (which is enabled by default). /// For more info on deriving `JsonSchema`, see [the derive macro documentation](derive@JsonSchema). /// /// # Examples /// Deriving an implementation: /// ``` /// use schemars::{schema_for, JsonSchema}; /// /// #[derive(JsonSchema)] /// struct MyStruct { /// foo: i32, /// } /// /// let my_schema = schema_for!(MyStruct); /// ``` /// /// When manually implementing `JsonSchema`, as well as determining an appropriate schema, /// you will need to determine an appropriate name and ID for the type. /// For non-generic types, the type name/path are suitable for this: /// ``` /// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema}; /// use std::borrow::Cow; /// /// struct NonGenericType; /// /// impl JsonSchema for NonGenericType { /// fn schema_name() -> Cow<'static, str> { /// // Exclude the module path to make the name in generated schemas clearer. /// "NonGenericType".into() /// } /// /// fn schema_id() -> Cow<'static, str> { /// // Include the module, in case a type with the same name is in another module/crate /// concat!(module_path!(), "::NonGenericType").into() /// } /// /// fn json_schema(_gen: &mut SchemaGenerator) -> Schema { /// json_schema!({ /// "foo": "bar" /// }) /// } /// } /// /// assert_eq!(NonGenericType::schema_id(), <&mut NonGenericType>::schema_id()); /// ``` /// /// But generic type parameters which may affect the generated schema should typically be included /// in the name/ID: /// ``` /// use schemars::{SchemaGenerator, Schema, JsonSchema, json_schema}; /// use std::{borrow::Cow, marker::PhantomData}; /// /// struct GenericType(PhantomData); /// /// impl JsonSchema for GenericType { /// fn schema_name() -> Cow<'static, str> { /// format!("GenericType_{}", T::schema_name()).into() /// } /// /// fn schema_id() -> Cow<'static, str> { /// format!( /// "{}::GenericType<{}>", /// module_path!(), /// T::schema_id() /// ).into() /// } /// /// fn json_schema(_gen: &mut SchemaGenerator) -> Schema { /// json_schema!({ /// "foo": "bar" /// }) /// } /// } /// /// assert_eq!(>::schema_id(), <&mut GenericType<&i32>>::schema_id()); /// ``` pub trait JsonSchema { /// Whether JSON Schemas generated for this type should be included directly in parent schemas, /// rather than being re-used where possible using the `$ref` keyword. /// /// For trivial types (such as primitives), this should return `true`. For more complex types, /// it should return `false`. For recursive types, this **must** return `false` to prevent /// infinite cycles when generating schemas. /// /// By default, this returns `false`. #[must_use] fn inline_schema() -> bool { false } /// The name of the generated JSON Schema. /// /// This is used as the title for root schemas, and the key within the root's `definitions` /// property for subschemas. #[must_use] fn schema_name() -> Cow<'static, str>; /// Returns a string that uniquely identifies the schema produced by this type. /// /// This does not have to be a human-readable string, and the value will not itself be included /// in generated schemas. If two types produce different schemas, then they **must** have /// different `schema_id()`s, but two types that produce identical schemas should *ideally* /// have the same `schema_id()`. /// /// The default implementation returns the same value as /// [`schema_name()`](JsonSchema::schema_name). #[must_use] fn schema_id() -> Cow<'static, str> { Self::schema_name() } /// Generates a JSON Schema for this type. /// /// If the returned schema depends on any [non-inlined](JsonSchema::inline_schema) /// schemas, then this method will add them to the [`SchemaGenerator`]'s schema definitions. /// /// This should not return a `$ref` schema. fn json_schema(generator: &mut SchemaGenerator) -> Schema; // TODO document and bring into public API? #[doc(hidden)] fn _schemars_private_non_optional_json_schema(generator: &mut SchemaGenerator) -> Schema { Self::json_schema(generator) } // TODO document and bring into public API? #[doc(hidden)] #[must_use] fn _schemars_private_is_option() -> bool { false } } schemars-1.2.1/src/macros.rs000064400000000000000000000073741046102023000140660ustar 00000000000000/// Generates a [`Schema`](crate::Schema) for the given type using default settings. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// /// The type must implement [`JsonSchema`](crate::JsonSchema). /// /// # Example /// ``` /// use schemars::{schema_for, JsonSchema}; /// /// #[derive(JsonSchema)] /// struct MyStruct { /// foo: i32, /// } /// /// let my_schema = schema_for!(MyStruct); /// ``` #[cfg(doc)] #[macro_export] macro_rules! schema_for { ($type:ty) => { $crate::SchemaGenerator::default().into_root_schema_for::<$type>() }; } /// Generates a [`Schema`](crate::Schema) for the given type using default settings. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// /// The type must implement [`JsonSchema`](crate::JsonSchema). /// /// # Example /// ``` /// use schemars::{schema_for, JsonSchema}; /// /// #[derive(JsonSchema)] /// struct MyStruct { /// foo: i32, /// } /// /// let my_schema = schema_for!(MyStruct); /// ``` #[cfg(not(doc))] #[macro_export] macro_rules! schema_for { ($type:ty) => { $crate::SchemaGenerator::default().into_root_schema_for::<$type>() }; ($_:expr) => { compile_error!("This argument to `schema_for!` is not a type - did you mean to use `schema_for_value!` instead?") }; } /// Generates a [`Schema`](crate::Schema) for the given example value using default settings. /// The default settings currently conform to [JSON Schema 2020-12](https://json-schema.org/specification-links#2020-12), but this is liable to change in a future version of Schemars if support for other JSON Schema versions is added. /// /// The value must implement [`Serialize`](serde::Serialize). If the value also implements /// [`JsonSchema`](crate::JsonSchema), then prefer using the [`schema_for!(Type)`](schema_for) macro /// which will generally produce a more precise schema, particularly when the value contains any /// enums. /// /// If the `Serialize` implementation of the value decides to fail, this macro will panic. /// For a non-panicking alternative, create a [`SchemaGenerator`](crate::SchemaGenerator) and use /// its [`into_root_schema_for_value`](crate::SchemaGenerator::into_root_schema_for_value) method. /// /// # Example /// ``` /// use schemars::schema_for_value; /// /// #[derive(serde::Serialize)] /// struct MyStruct { /// foo: i32, /// } /// /// let my_schema = schema_for_value!(MyStruct { foo: 123 }); /// ``` #[macro_export] macro_rules! schema_for_value { ($value:expr) => { $crate::SchemaGenerator::default() .into_root_schema_for_value(&$value) .unwrap() }; } /// Construct a [`Schema`](crate::Schema) from a JSON literal. This can either be a JSON object, or /// a boolean (`true` or `false`). /// /// You can interpolate variables or expressions into a JSON object using the same rules as the /// [`serde_json::json`] macro. /// /// # Example /// ``` /// use schemars::{Schema, json_schema}; /// /// let desc = "A helpful description."; /// let my_schema: Schema = json_schema!({ /// "description": desc, /// "type": ["object", "null"] /// }); /// ``` #[macro_export] macro_rules! json_schema { ( {$($json_object:tt)*} ) => { <$crate::Schema as ::core::convert::TryFrom<_>>::try_from($crate::_private::serde_json::json!({$($json_object)*})).unwrap() }; (true) => { $crate::Schema::from(true) }; (false) => { $crate::Schema::from(false) }; } schemars-1.2.1/src/schema.rs000064400000000000000000000471141046102023000140360ustar 00000000000000/*! JSON Schema types. */ use crate::_alloc_prelude::*; use ref_cast::{ref_cast_custom, RefCastCustom}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; /// A JSON Schema. /// /// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a /// [bool](Value::Bool). /// /// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro: /// ``` /// use schemars::{Schema, json_schema}; /// /// let my_schema: Schema = json_schema!({ /// "type": ["object", "null"] /// }); /// ``` /// /// Because a `Schema` is a thin wrapper around a `Value`, you can also use /// [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`. /// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can /// be converted in this way. /// /// ``` /// use schemars::{Schema, json_schema}; /// use serde_json::json; /// /// let json_object = json!({"type": ["object", "null"]}); /// let object_schema: Schema = json_object.try_into().unwrap(); /// /// let json_bool = json!(true); /// let bool_schema: Schema = json_bool.try_into().unwrap(); /// /// let json_string = json!("This is neither an object nor a bool!"); /// assert!(Schema::try_from(json_string).is_err()); /// /// // You can also convert a `&Value`/`&mut Value` to a `&Schema`/`&mut Schema` the same way: /// /// let json_object = json!({"type": ["object", "null"]}); /// let object_schema_ref: &Schema = (&json_object).try_into().unwrap(); /// /// let mut json_object = json!({"type": ["object", "null"]}); /// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap(); /// ``` /// /// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing /// [`Map`] or [`bool`]. /// /// ``` /// use schemars::{Schema, json_schema}; /// use serde_json::{Map, json}; /// /// let mut map = Map::new(); /// map.insert("type".to_owned(), json!(["object", "null"])); /// let object_schema: Schema = map.into(); /// /// let bool_schema: Schema = true.into(); /// ``` #[derive(Debug, Clone, PartialEq, RefCastCustom)] #[repr(transparent)] pub struct Schema(Value); impl<'de> Deserialize<'de> for Schema { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let value = Value::deserialize(deserializer)?; Schema::validate(&value)?; Ok(Schema(value)) } } impl Serialize for Schema { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { ser::OrderedKeywordWrapper::from(&self.0).serialize(serializer) } } impl PartialEq for Schema { fn eq(&self, other: &bool) -> bool { self.as_bool() == Some(*other) } } impl PartialEq> for Schema { fn eq(&self, other: &Map) -> bool { self.as_object() == Some(other) } } impl PartialEq for Schema { fn eq(&self, other: &Value) -> bool { self.as_value() == other } } impl PartialEq for bool { fn eq(&self, other: &Schema) -> bool { other == self } } impl PartialEq for Map { fn eq(&self, other: &Schema) -> bool { other == self } } impl PartialEq for Value { fn eq(&self, other: &Schema) -> bool { other == self } } impl Schema { /// Creates a new schema object with a single string property `"$ref"`. /// /// The given reference string should be a URI reference. This will usually be a JSON Pointer /// in [URI Fragment representation](https://tools.ietf.org/html/rfc6901#section-6). #[must_use] pub fn new_ref(reference: String) -> Self { let mut map = Map::new(); map.insert("$ref".to_owned(), Value::String(reference)); Self(Value::Object(map)) } /// Borrows the `Schema`'s underlying JSON value. #[must_use] pub fn as_value(&self) -> &Value { &self.0 } /// If the `Schema`'s underlying JSON value is a bool, returns the bool value. #[must_use] pub fn as_bool(&self) -> Option { self.0.as_bool() } /// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of /// properties. #[must_use] pub fn as_object(&self) -> Option<&Map> { self.0.as_object() } /// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map` /// of properties. #[must_use] pub fn as_object_mut(&mut self) -> Option<&mut Map> { self.0.as_object_mut() } pub(crate) fn try_to_object(self) -> Result, bool> { match self.0 { Value::Object(m) => Ok(m), Value::Bool(b) => Err(b), _ => unreachable!(), } } pub(crate) fn try_as_object_mut(&mut self) -> Result<&mut Map, bool> { match &mut self.0 { Value::Object(m) => Ok(m), Value::Bool(b) => Err(*b), _ => unreachable!(), } } /// Returns the `Schema`'s underlying JSON value. #[must_use] pub fn to_value(self) -> Value { self.0 } /// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then /// mutably borrows the object as a `Map` of properties. /// /// `true` is transformed into an empty schema `{}`, which successfully validates against all /// possible values. `false` is transformed into the schema `{"not": {}}`, which does not /// successfully validate against any value. #[allow(clippy::missing_panics_doc)] pub fn ensure_object(&mut self) -> &mut Map { if let Some(b) = self.as_bool() { let mut map = Map::new(); if !b { map.insert("not".into(), Value::Object(Map::new())); } self.0 = Value::Object(map); } self.0 .as_object_mut() .expect("Schema value should be of type Object.") } /// Inserts a property into the schema, replacing any previous value. /// /// If the schema wraps a bool value, it will first be converted into an equivalent object /// schema. /// /// If the schema did not have this key present, `None` is returned. /// /// If the schema did have this key present, the value is updated, and the old value is /// returned. /// /// # Example /// ``` /// use schemars::json_schema; /// use serde_json::json; /// /// let mut schema = json_schema!(true); /// assert_eq!(schema.insert("type".to_owned(), "array".into()), None); /// assert_eq!(schema.insert("type".to_owned(), "object".into()), Some(json!("array"))); /// /// assert_eq!(schema, json_schema!({"type": "object"})); /// ``` pub fn insert(&mut self, k: String, v: Value) -> Option { self.ensure_object().insert(k, v) } /// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's /// value for the given key if it exists. /// /// This always returns `None` for bool schemas. /// /// # Example /// ``` /// use schemars::json_schema; /// use serde_json::json; /// /// let obj_schema = json_schema!({"type": "array"}); /// assert_eq!(obj_schema.get("type"), Some(&json!("array"))); /// assert_eq!(obj_schema.get("format"), None); /// /// let bool_schema = json_schema!(true); /// assert_eq!(bool_schema.get("type"), None); /// ``` #[must_use] pub fn get(&self, key: &Q) -> Option<&Value> where String: core::borrow::Borrow, Q: ?Sized + Ord + Eq + core::hash::Hash, { self.0.as_object().and_then(|o| o.get(key)) } /// If the `Schema`'s underlying JSON value is an object, gets a mutable reference to that /// object's value for the given key if it exists. /// /// This always returns `None` for bool schemas. /// /// # Example /// ``` /// use schemars::json_schema; /// use serde_json::{json, Value}; /// /// let mut obj_schema = json_schema!({ "properties": {} }); /// if let Some(Value::Object(properties)) = obj_schema.get_mut("properties") { /// properties.insert("anything".to_owned(), true.into()); /// } /// assert_eq!(obj_schema, json_schema!({ "properties": { "anything": true } })); /// ``` #[must_use] pub fn get_mut(&mut self, key: &Q) -> Option<&mut Value> where String: core::borrow::Borrow, Q: ?Sized + Ord + Eq + core::hash::Hash, { self.0.as_object_mut().and_then(|o| o.get_mut(key)) } /// If the `Schema`'s underlying JSON value is an object, looks up a value within the schema /// by a JSON Pointer. /// /// If the given pointer begins with a `#`, then the rest of the value is assumed to be in /// "URI Fragment Identifier Representation", and will be percent-decoded accordingly. /// /// For more information on JSON Pointer, read [RFC6901](https://tools.ietf.org/html/rfc6901). /// /// This always returns `None` for bool schemas. /// /// # Example /// ``` /// use schemars::json_schema; /// use serde_json::json; /// /// let schema = json_schema!({ /// "properties": { /// "anything": true /// }, /// "$defs": { /// "🚀": true /// } /// }); /// /// assert_eq!(schema.pointer("/properties/anything").unwrap(), &json!(true)); /// assert_eq!(schema.pointer("#/$defs/%F0%9F%9A%80").unwrap(), &json!(true)); /// assert_eq!(schema.pointer("/does/not/exist"), None); /// ``` #[must_use] pub fn pointer(&self, pointer: &str) -> Option<&Value> { if let Some(percent_encoded) = pointer.strip_prefix('#') { let decoded = crate::encoding::percent_decode(percent_encoded)?; self.0.pointer(&decoded) } else { self.0.pointer(pointer) } } /// If the `Schema`'s underlying JSON value is an object, looks up a value by a JSON Pointer /// and returns a mutable reference to that value. /// /// If the given pointer begins with a `#`, then the rest of the value is assumed to be in /// "URI Fragment Identifier Representation", and will be percent-decoded accordingly. /// /// For more information on JSON Pointer, read [RFC6901](https://tools.ietf.org/html/rfc6901). /// /// This always returns `None` for bool schemas. /// /// # Example /// ``` /// use schemars::{json_schema, Schema}; /// use serde_json::json; /// /// let mut schema = json_schema!({ /// "properties": { /// "anything": true /// }, /// "$defs": { /// "🚀": true /// } /// }); /// /// assert_eq!(schema.pointer_mut("/properties/anything").unwrap(), &json!(true)); /// assert_eq!(schema.pointer_mut("#/$defs/%F0%9F%9A%80").unwrap(), &json!(true)); /// assert_eq!(schema.pointer_mut("/does/not/exist"), None); /// ``` #[must_use] pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Value> { if let Some(percent_encoded) = pointer.strip_prefix('#') { let decoded = crate::encoding::percent_decode(percent_encoded)?; self.0.pointer_mut(&decoded) } else { self.0.pointer_mut(pointer) } } /// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the /// given key. /// /// This always returns `None` for bool schemas, without modifying them. /// /// # Example /// ``` /// use schemars::json_schema; /// use serde_json::json; /// /// let mut schema = json_schema!({"type": "array"}); /// assert_eq!(schema.remove("type"), Some(json!("array"))); /// assert_eq!(schema, json_schema!({})); /// ``` pub fn remove(&mut self, key: &Q) -> Option where String: core::borrow::Borrow, Q: ?Sized + Ord + Eq + core::hash::Hash, { self.0.as_object_mut().and_then(|o| o.remove(key)) } pub(crate) fn has_type(&self, ty: &str) -> bool { match self.0.get("type") { Some(Value::Array(values)) => values.iter().any(|v| v.as_str() == Some(ty)), Some(Value::String(s)) => s == ty, _ => false, } } fn validate(value: &Value) -> Result<(), E> { use serde::de::Unexpected; let unexpected = match value { Value::Bool(_) | Value::Object(_) => return Ok(()), Value::Null => Unexpected::Unit, Value::Number(n) => { if let Some(u) = n.as_u64() { Unexpected::Unsigned(u) } else if let Some(i) = n.as_i64() { Unexpected::Signed(i) } else if let Some(f) = n.as_f64() { Unexpected::Float(f) } else { unreachable!() } } Value::String(s) => Unexpected::Str(s), Value::Array(_) => Unexpected::Seq, }; Err(E::invalid_type(unexpected, &"object or boolean")) } #[ref_cast_custom] fn ref_cast(value: &Value) -> &Self; #[ref_cast_custom] fn ref_cast_mut(value: &mut Value) -> &mut Self; } impl From for Value { fn from(v: Schema) -> Value { v.0 } } impl core::convert::TryFrom for Schema { type Error = serde_json::Error; fn try_from(value: Value) -> serde_json::Result { Schema::validate(&value)?; Ok(Schema(value)) } } impl<'a> core::convert::TryFrom<&'a Value> for &'a Schema { type Error = serde_json::Error; fn try_from(value: &Value) -> serde_json::Result<&Schema> { Schema::validate(value)?; Ok(Schema::ref_cast(value)) } } impl<'a> core::convert::TryFrom<&'a mut Value> for &'a mut Schema { type Error = serde_json::Error; fn try_from(value: &mut Value) -> serde_json::Result<&mut Schema> { Schema::validate(value)?; Ok(Schema::ref_cast_mut(value)) } } impl Default for Schema { fn default() -> Self { Self(Value::Object(Map::new())) } } impl From> for Schema { fn from(o: Map) -> Self { Schema(Value::Object(o)) } } impl From for Schema { fn from(b: bool) -> Self { Schema(Value::Bool(b)) } } impl crate::JsonSchema for Schema { fn schema_name() -> alloc::borrow::Cow<'static, str> { "Schema".into() } fn schema_id() -> alloc::borrow::Cow<'static, str> { "schemars::Schema".into() } fn json_schema(_: &mut crate::SchemaGenerator) -> Schema { crate::json_schema!({ "type": ["object", "boolean"] }) } } mod ser { use serde::ser::{Serialize, SerializeMap, SerializeSeq}; use serde_json::Value; // The order of properties in a JSON Schema object is insignificant, but we explicitly order // some of them here to make them easier for a human to read. All other properties are ordered // either lexicographically (by default) or by insertion order (if `preserve_order` is enabled) const ORDERED_KEYWORDS_START: [&str; 7] = [ "$id", "$schema", "title", "description", "type", "format", "properties", ]; const ORDERED_KEYWORDS_END: [&str; 2] = ["$defs", "definitions"]; // `no_reorder` is true when the value is expected to be an object that is NOT a schema, // but the object's property values are expected to be schemas. In this case, we do not // reorder the object's direct properties, but we do reorder nested (subschema) properties. // // When `no_reorder` is false, then the value is expected to be one of: // - a JSON schema object // - an array of JSON schemas // - a JSON primitive value (null/string/number/bool) // // If any of these expectations are not met, then the value should still be serialized in a // valid way, but the property ordering may be unclear. pub(super) struct OrderedKeywordWrapper<'a> { value: &'a Value, no_reorder: bool, } impl<'a> From<&'a Value> for OrderedKeywordWrapper<'a> { fn from(value: &'a Value) -> Self { Self { value, no_reorder: false, } } } impl Serialize for OrderedKeywordWrapper<'_> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { fn serialize_schema_property( map: &mut S::SerializeMap, key: &str, value: &Value, ) -> Result<(), S::Error> where S: serde::Serializer, { if matches!(key, "examples" | "default") || key.starts_with("x-") { // Value(s) of `examples`/`default` are plain values, not schemas. // Also don't reorder values of custom properties. map.serialize_entry(key, value) } else { let no_reorder = matches!( key, "properties" | "patternProperties" | "dependentSchemas" | "$defs" | "definitions" ); map.serialize_entry(key, &OrderedKeywordWrapper { value, no_reorder }) } } match self.value { Value::Array(array) => { let mut seq = serializer.serialize_seq(Some(array.len()))?; for value in array { seq.serialize_element(&OrderedKeywordWrapper::from(value))?; } seq.end() } Value::Object(object) if self.no_reorder => { let mut map = serializer.serialize_map(Some(object.len()))?; for (key, value) in object { // Don't use `serialize_schema_property` because `object` is NOT expected // to be a schema (but `value` is expected to be a schema) map.serialize_entry(key, &OrderedKeywordWrapper::from(value))?; } map.end() } Value::Object(object) => { let mut map = serializer.serialize_map(Some(object.len()))?; for key in ORDERED_KEYWORDS_START { if let Some(value) = object.get(key) { serialize_schema_property::(&mut map, key, value)?; } } for (key, value) in object { if !ORDERED_KEYWORDS_START.contains(&key.as_str()) && !ORDERED_KEYWORDS_END.contains(&key.as_str()) { serialize_schema_property::(&mut map, key, value)?; } } for key in ORDERED_KEYWORDS_END { if let Some(value) = object.get(key) { serialize_schema_property::(&mut map, key, value)?; } } map.end() } Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { self.value.serialize(serializer) } } } } } schemars-1.2.1/src/ser.rs000064400000000000000000000276611046102023000133740ustar 00000000000000use crate::_alloc_prelude::*; use crate::_private::allow_null; use crate::{json_schema, Schema, SchemaGenerator}; use core::fmt::Display; use serde_json::{Error, Map, Value}; pub(crate) struct Serializer<'a> { pub(crate) generator: &'a mut SchemaGenerator, pub(crate) include_title: bool, } pub(crate) struct SerializeSeq<'a> { generator: &'a mut SchemaGenerator, items: Vec, } pub(crate) struct SerializeTuple<'a> { generator: &'a mut SchemaGenerator, items: Vec, title: &'static str, } pub(crate) struct SerializeMap<'a> { generator: &'a mut SchemaGenerator, properties: Map, current_key: Option, title: &'static str, } macro_rules! forward_to_subschema_for { ($fn:ident, $ty:ty) => { fn $fn(self, _value: $ty) -> Result { Ok(self.generator.subschema_for::<$ty>()) } }; } macro_rules! return_instance_type { ($fn:ident, $ty:ty, $instance_type:expr) => { fn $fn(self, _value: $ty) -> Result { Ok(json_schema!({ "type": $instance_type })) } }; } impl<'a> serde::Serializer for Serializer<'a> { type Ok = Schema; type Error = Error; type SerializeSeq = SerializeSeq<'a>; type SerializeTuple = SerializeTuple<'a>; type SerializeTupleStruct = SerializeTuple<'a>; type SerializeTupleVariant = Self; type SerializeMap = SerializeMap<'a>; type SerializeStruct = SerializeMap<'a>; type SerializeStructVariant = Self; return_instance_type!(serialize_i8, i8, "integer"); return_instance_type!(serialize_i16, i16, "integer"); return_instance_type!(serialize_i32, i32, "integer"); return_instance_type!(serialize_i64, i64, "integer"); return_instance_type!(serialize_i128, i128, "integer"); return_instance_type!(serialize_u8, u8, "integer"); return_instance_type!(serialize_u16, u16, "integer"); return_instance_type!(serialize_u32, u32, "integer"); return_instance_type!(serialize_u64, u64, "integer"); return_instance_type!(serialize_u128, u128, "integer"); return_instance_type!(serialize_f32, f32, "number"); return_instance_type!(serialize_f64, f64, "number"); forward_to_subschema_for!(serialize_bool, bool); forward_to_subschema_for!(serialize_char, char); forward_to_subschema_for!(serialize_str, &str); forward_to_subschema_for!(serialize_bytes, &[u8]); fn collect_str(self, _value: &T) -> Result where T: Display + ?Sized, { Ok(self.generator.subschema_for::<&str>()) } fn collect_map(self, iter: I) -> Result where K: serde::Serialize, V: serde::Serialize, I: IntoIterator, { let value_schema = iter .into_iter() .try_fold(None, |acc, (_, v)| { if acc == Some(true.into()) { return Ok(acc); } let schema = v.serialize(Serializer { generator: self.generator, include_title: false, })?; Ok(match &acc { None => Some(schema), Some(items) if items != &schema => Some(true.into()), _ => acc, }) })? .unwrap_or(true.into()); Ok(json_schema!({ "type": "object", "additionalProperties": value_schema, })) } fn serialize_none(self) -> Result { Ok(self.generator.subschema_for::()) } fn serialize_unit(self) -> Result { self.serialize_none() } fn serialize_some(self, value: &T) -> Result where T: serde::Serialize + ?Sized, { let mut schema = value.serialize(Serializer { generator: self.generator, include_title: false, })?; allow_null(self.generator, &mut schema); Ok(schema) } fn serialize_unit_struct(self, _name: &'static str) -> Result { Ok(self.generator.subschema_for::<()>()) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Ok(true.into()) } fn serialize_newtype_struct( self, name: &'static str, value: &T, ) -> Result where T: serde::Serialize + ?Sized, { let include_title = self.include_title; let mut schema = value.serialize(self)?; if include_title && !name.is_empty() { schema.insert("title".into(), name.into()); } Ok(schema) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result where T: serde::Serialize + ?Sized, { Ok(true.into()) } fn serialize_seq(self, _len: Option) -> Result { Ok(SerializeSeq { generator: self.generator, items: Vec::new(), }) } fn serialize_tuple(self, len: usize) -> Result { Ok(SerializeTuple { generator: self.generator, items: Vec::with_capacity(len), title: "", }) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { let title = if self.include_title { name } else { "" }; Ok(SerializeTuple { generator: self.generator, items: Vec::with_capacity(len), title, }) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Ok(self) } fn serialize_map(self, _len: Option) -> Result { Ok(SerializeMap { generator: self.generator, properties: Map::new(), current_key: None, title: "", }) } fn serialize_struct( self, name: &'static str, _len: usize, ) -> Result { let title = if self.include_title { name } else { "" }; Ok(SerializeMap { generator: self.generator, properties: Map::new(), current_key: None, title, }) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Ok(self) } } impl serde::ser::SerializeTupleVariant for Serializer<'_> { type Ok = Schema; type Error = Error; fn serialize_field(&mut self, _value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { Ok(()) } fn end(self) -> Result { Ok(true.into()) } } impl serde::ser::SerializeStructVariant for Serializer<'_> { type Ok = Schema; type Error = Error; fn serialize_field(&mut self, _key: &'static str, _value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { Ok(()) } fn end(self) -> Result { Ok(true.into()) } } impl serde::ser::SerializeSeq for SerializeSeq<'_> { type Ok = Schema; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { if self.items.first() == Some(&true.into()) { // Schema already allows any value, so no point in extending it return Ok(()); } let schema = value.serialize(Serializer { generator: self.generator, include_title: false, })?; if schema == true { self.items = vec![schema]; } else if !self.items.contains(&schema) { self.items.push(schema); } Ok(()) } fn end(mut self) -> Result { let items = match self.items.len() { 0 => true.into(), 1 => self.items.remove(0), _ => json_schema!({ "anyOf": self.items }), }; Ok(json_schema!({ "type": "array", "items": items })) } } impl serde::ser::SerializeTuple for SerializeTuple<'_> { type Ok = Schema; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { let schema = value.serialize(Serializer { generator: self.generator, include_title: false, })?; self.items.push(schema); Ok(()) } fn end(self) -> Result { let len = self.items.len(); let mut schema = json_schema!({ "type": "array", "prefixItems": self.items, "maxItems": len, "minItems": len, }); if !self.title.is_empty() { schema .ensure_object() .insert("title".into(), self.title.into()); } Ok(schema) } } impl serde::ser::SerializeTupleStruct for SerializeTuple<'_> { type Ok = Schema; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { serde::ser::SerializeTuple::serialize_element(self, value) } fn end(self) -> Result { serde::ser::SerializeTuple::end(self) } } impl serde::ser::SerializeMap for SerializeMap<'_> { type Ok = Schema; type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { // FIXME this is too lenient - we should return an error if serde_json // doesn't allow T to be a key of a map. let json = serde_json::to_string(key)?; self.current_key = Some( json.trim_start_matches('"') .trim_end_matches('"') .to_string(), ); Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { let key = self.current_key.take().unwrap_or_default(); let schema = value.serialize(Serializer { generator: self.generator, include_title: false, })?; self.properties.insert(key, schema.into()); Ok(()) } fn end(self) -> Result { let mut schema = json_schema!({ "type": "object", "properties": self.properties, }); if !self.title.is_empty() { schema .ensure_object() .insert("title".into(), self.title.into()); } Ok(schema) } } impl serde::ser::SerializeStruct for SerializeMap<'_> { type Ok = Schema; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: serde::Serialize + ?Sized, { let prop_schema = value.serialize(Serializer { generator: self.generator, include_title: false, })?; self.properties.insert(key.to_string(), prop_schema.into()); Ok(()) } fn end(self) -> Result { serde::ser::SerializeMap::end(self) } } schemars-1.2.1/src/transform.rs000064400000000000000000000564031046102023000146120ustar 00000000000000/*! Contains the [`Transform`] trait, used to modify a constructed schema and optionally its subschemas. This trait is automatically implemented for functions of the form `fn(&mut Schema) -> ()`. # Recursive Transforms To make a transform recursive (i.e. apply it to subschemas), you have two options: 1. call the [`transform_subschemas`] function within the transform function 2. wrap the `Transform` in a [`RecursiveTransform`] # Examples To add a custom property to all object schemas: ``` # use schemars::{Schema, json_schema}; use schemars::transform::{Transform, transform_subschemas}; pub struct MyTransform; impl Transform for MyTransform { fn transform(&mut self, schema: &mut Schema) { // First, make our change to this schema schema.insert("my_property".to_string(), "hello world".into()); // Then apply the transform to any subschemas transform_subschemas(self, schema); } } let mut schema = json_schema!({ "type": "array", "items": {} }); MyTransform.transform(&mut schema); assert_eq!( schema, json_schema!({ "type": "array", "items": { "my_property": "hello world" }, "my_property": "hello world" }) ); ``` The same example with a `fn` transform: ``` # use schemars::{Schema, json_schema}; use schemars::transform::transform_subschemas; fn add_property(schema: &mut Schema) { schema.insert("my_property".to_string(), "hello world".into()); transform_subschemas(&mut add_property, schema) } let mut schema = json_schema!({ "type": "array", "items": {} }); add_property(&mut schema); assert_eq!( schema, json_schema!({ "type": "array", "items": { "my_property": "hello world" }, "my_property": "hello world" }) ); ``` And the same example using a closure wrapped in a `RecursiveTransform`: ``` # use schemars::{Schema, json_schema}; use schemars::transform::{Transform, RecursiveTransform}; let mut transform = RecursiveTransform(|schema: &mut Schema| { schema.insert("my_property".to_string(), "hello world".into()); }); let mut schema = json_schema!({ "type": "array", "items": {} }); transform.transform(&mut schema); assert_eq!( schema, json_schema!({ "type": "array", "items": { "my_property": "hello world" }, "my_property": "hello world" }) ); ``` */ use crate::_alloc_prelude::*; use crate::{consts::meta_schemas, Schema}; use alloc::borrow::Cow; use alloc::collections::BTreeSet; use serde_json::{json, Map, Value}; /// Trait used to modify a constructed schema and optionally its subschemas. /// /// See the [module documentation](self) for more details on implementing this trait. pub trait Transform { /// Applies the transform to the given [`Schema`]. /// /// When overriding this method, you may want to call the [`transform_subschemas`] function to /// also transform any subschemas. fn transform(&mut self, schema: &mut Schema); // Not public API // Hack to enable implementing Debug on Box even though closures don't // implement Debug #[doc(hidden)] fn _debug_type_name(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str(core::any::type_name::()) } } impl Transform for F where F: FnMut(&mut Schema), { fn transform(&mut self, schema: &mut Schema) { self(schema); } } /// Applies the given [`Transform`] to all direct subschemas of the [`Schema`]. pub fn transform_subschemas(t: &mut T, schema: &mut Schema) { for (key, value) in schema.as_object_mut().into_iter().flatten() { // This is intentionally written to work with multiple JSON Schema versions, so that // users can add their own transforms on the end of e.g. `SchemaSettings::draft07()` and // they will still apply to all subschemas "as expected". // This is why this match statement contains both `additionalProperties` (which was // dropped in draft 2020-12) and `prefixItems` (which was added in draft 2020-12). match key.as_str() { "not" | "if" | "then" | "else" | "contains" | "additionalProperties" | "propertyNames" | "additionalItems" => { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } "allOf" | "anyOf" | "oneOf" | "prefixItems" => { if let Some(array) = value.as_array_mut() { for value in array { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } } } // Support `items` array even though this is not allowed in draft 2020-12 (see above // comment) "items" => { if let Some(array) = value.as_array_mut() { for value in array { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } } else if let Ok(subschema) = value.try_into() { t.transform(subschema); } } "properties" | "patternProperties" | "$defs" | "definitions" => { if let Some(obj) = value.as_object_mut() { for value in obj.values_mut() { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } } } _ => {} } } } // Similar to `transform_subschemas`, but only transforms subschemas that apply to the top-level // object, e.g. "oneOf" but not "properties". pub(crate) fn transform_immediate_subschemas( t: &mut T, schema: &mut Schema, ) { for (key, value) in schema.as_object_mut().into_iter().flatten() { match key.as_str() { "if" | "then" | "else" => { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } "allOf" | "anyOf" | "oneOf" => { if let Some(array) = value.as_array_mut() { for value in array { if let Ok(subschema) = value.try_into() { t.transform(subschema); } } } } _ => {} } } } /// A helper struct that can wrap a non-recursive [`Transform`] (i.e. one that does not apply to /// subschemas) into a recursive one. /// /// Its implementation of `Transform` will first apply the inner transform to the "parent" schema, /// and then its subschemas (and their subschemas, and so on). /// /// # Example /// ``` /// # use schemars::{Schema, json_schema}; /// use schemars::transform::{Transform, RecursiveTransform}; /// /// let mut transform = RecursiveTransform(|schema: &mut Schema| { /// schema.insert("my_property".to_string(), "hello world".into()); /// }); /// /// let mut schema = json_schema!({ /// "type": "array", /// "items": {} /// }); /// /// transform.transform(&mut schema); /// /// assert_eq!( /// schema, /// json_schema!({ /// "type": "array", /// "items": { /// "my_property": "hello world" /// }, /// "my_property": "hello world" /// }) /// ); /// ``` #[derive(Debug, Clone)] #[allow(clippy::exhaustive_structs)] pub struct RecursiveTransform(pub T); impl Transform for RecursiveTransform where T: Transform, { fn transform(&mut self, schema: &mut Schema) { self.0.transform(schema); transform_subschemas(self, schema); } } /// Replaces boolean JSON Schemas with equivalent object schemas. /// /// This also applies to subschemas. /// /// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support booleans as /// schemas. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct ReplaceBoolSchemas { /// When set to `true`, a schema's `additionalProperties` property will not be changed from a /// boolean. /// /// Defaults to `false`. pub skip_additional_properties: bool, } impl Transform for ReplaceBoolSchemas { fn transform(&mut self, schema: &mut Schema) { if let Some(obj) = schema.as_object_mut() { if self.skip_additional_properties { if let Some((ap_key, ap_value)) = obj.remove_entry("additionalProperties") { transform_subschemas(self, schema); schema.insert(ap_key, ap_value); return; } } transform_subschemas(self, schema); } else { schema.ensure_object(); } } } /// Restructures JSON Schema objects so that the `$ref` property will never appear alongside any /// other properties. /// /// This also applies to subschemas. /// /// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support other properties /// alongside `$ref`. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct RemoveRefSiblings; impl Transform for RemoveRefSiblings { fn transform(&mut self, schema: &mut Schema) { transform_subschemas(self, schema); if let Some(obj) = schema.as_object_mut().filter(|o| o.len() > 1) { if let Some(ref_value) = obj.remove("$ref") { if let Value::Array(all_of) = obj.entry("allOf").or_insert(Value::Array(Vec::new())) { all_of.push(json!({ "$ref": ref_value })); } } } } } /// Removes the `examples` schema property and (if present) set its first value as the `example` /// property. /// /// This also applies to subschemas. /// /// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `examples` /// property. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct SetSingleExample; impl Transform for SetSingleExample { fn transform(&mut self, schema: &mut Schema) { transform_subschemas(self, schema); if let Some(Value::Array(examples)) = schema.remove("examples") { if let Some(first_example) = examples.into_iter().next() { schema.insert("example".into(), first_example); } } } } /// Replaces the `const` schema property with a single-valued `enum` property. /// /// This also applies to subschemas. /// /// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const` /// property. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct ReplaceConstValue; impl Transform for ReplaceConstValue { fn transform(&mut self, schema: &mut Schema) { transform_subschemas(self, schema); if let Some(value) = schema.remove("const") { schema.insert("enum".into(), Value::Array(vec![value])); } } } /// Rename the `prefixItems` schema property to `items`. /// /// This also applies to subschemas. /// /// If the schema contains both `prefixItems` and `items`, then this additionally renames `items` to /// `additionalItems`. /// /// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the `prefixItems` /// property. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct ReplacePrefixItems; impl Transform for ReplacePrefixItems { fn transform(&mut self, schema: &mut Schema) { transform_subschemas(self, schema); if let Some(prefix_items) = schema.remove("prefixItems") { let previous_items = schema.insert("items".to_owned(), prefix_items); if let Some(previous_items) = previous_items { schema.insert("additionalItems".to_owned(), previous_items); } } } } /// Adds a `"nullable": true` property to schemas that allow `null` types. /// /// This also applies to subschemas. /// /// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that use `nullable` instead of /// explicit null types. #[derive(Debug, Clone)] #[non_exhaustive] pub struct AddNullable { /// When set to `true` (the default), `"null"` will also be removed from the schemas `type`. pub remove_null_type: bool, /// When set to `true` (the default), a schema that has a type only allowing `null` will also /// have the equivalent `"const": null` inserted. pub add_const_null: bool, } impl Default for AddNullable { fn default() -> Self { Self { remove_null_type: true, add_const_null: true, } } } impl Transform for AddNullable { fn transform(&mut self, schema: &mut Schema) { if schema.has_type("null") { schema.insert("nullable".into(), true.into()); // has_type returned true so we know "type" exists and is a string or array let ty = schema.get_mut("type").unwrap(); let only_allows_null = ty.is_string() || ty.as_array().unwrap().iter().all(|v| v == "null"); if only_allows_null { if self.add_const_null { schema.insert("const".to_string(), Value::Null); if self.remove_null_type { schema.remove("type"); } } else if self.remove_null_type { *ty = Value::Array(Vec::new()); } } else if self.remove_null_type { // We know `type` is an array containing at least one non-null type let array = ty.as_array_mut().unwrap(); array.retain(|t| t != "null"); if array.len() == 1 { *ty = array.remove(0); } } } transform_subschemas(self, schema); } } /// Replaces the `unevaluatedProperties` schema property with the `additionalProperties` property, /// adding properties from a schema's subschemas to its `properties` where necessary. /// /// This also applies to subschemas. /// /// This is useful for versions of JSON Schema (e.g. Draft 7) that do not support the /// `unevaluatedProperties` property. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct ReplaceUnevaluatedProperties; impl Transform for ReplaceUnevaluatedProperties { fn transform(&mut self, schema: &mut Schema) { transform_subschemas(self, schema); let Some(up) = schema.remove("unevaluatedProperties") else { return; }; schema.insert("additionalProperties".to_owned(), up); let mut gather_property_names = GatherPropertyNames::default(); gather_property_names.transform(schema); let property_names = gather_property_names.0; if property_names.is_empty() { return; } if let Some(properties) = schema .ensure_object() .entry("properties") .or_insert(Map::new().into()) .as_object_mut() { for name in property_names { properties.entry(name).or_insert(true.into()); } } } } // Helper for getting property names for all *immediate* subschemas #[derive(Default)] struct GatherPropertyNames(BTreeSet); impl Transform for GatherPropertyNames { fn transform(&mut self, schema: &mut Schema) { self.0.extend( schema .as_object() .iter() .filter_map(|o| o.get("properties")) .filter_map(Value::as_object) .flat_map(Map::keys) .cloned(), ); transform_immediate_subschemas(self, schema); } } /// Removes any `format` values that are not defined by the JSON Schema standard or explicitly /// allowed by a custom list. /// /// This also applies to subschemas. /// /// By default, this will infer the version of JSON Schema from the schema's `$schema` property, /// and no additional formats will be allowed (even when the JSON schema allows nonstandard /// formats). /// /// # Example /// ``` /// use schemars::json_schema; /// use schemars::transform::{RestrictFormats, Transform}; /// /// let mut schema = schemars::json_schema!({ /// "$schema": "https://json-schema.org/draft/2020-12/schema", /// "anyOf": [ /// { /// "type": "string", /// "format": "uuid" /// }, /// { /// "$schema": "http://json-schema.org/draft-07/schema#", /// "type": "string", /// "format": "uuid" /// }, /// { /// "type": "string", /// "format": "allowed-custom-format" /// }, /// { /// "type": "string", /// "format": "forbidden-custom-format" /// } /// ] /// }); /// /// let mut transform = RestrictFormats::default(); /// transform.allowed_formats.insert("allowed-custom-format".into()); /// transform.transform(&mut schema); /// /// assert_eq!( /// schema, /// json_schema!({ /// "$schema": "https://json-schema.org/draft/2020-12/schema", /// "anyOf": [ /// { /// // "uuid" format is defined in draft 2020-12. /// "type": "string", /// "format": "uuid" /// }, /// { /// // "uuid" format is not defined in draft-07, so is removed from this subschema. /// "$schema": "http://json-schema.org/draft-07/schema#", /// "type": "string" /// }, /// { /// // "allowed-custom-format" format was present in `allowed_formats`... /// "type": "string", /// "format": "allowed-custom-format" /// }, /// { /// // ...but "forbidden-custom-format" format was not, so is also removed. /// "type": "string" /// } /// ] /// }) /// ); /// ``` #[derive(Debug, Clone)] #[non_exhaustive] pub struct RestrictFormats { /// Whether to read the schema's `$schema` property to determine which version of JSON Schema /// is being used, and allow only formats defined in that standard. If this is `true` but the /// JSON Schema version can't be determined because `$schema` is missing or unknown, then no /// `format` values will be removed. /// /// If this is set to `false`, then only the formats explicitly included in /// [`allowed_formats`](Self::allowed_formats) will be allowed. /// /// By default, this is `true`. pub infer_from_meta_schema: bool, /// Values of the `format` property in schemas that will always be allowed, regardless of the /// inferred version of JSON Schema. pub allowed_formats: BTreeSet>, } impl Default for RestrictFormats { fn default() -> Self { Self { infer_from_meta_schema: true, allowed_formats: BTreeSet::new(), } } } impl Transform for RestrictFormats { fn transform(&mut self, schema: &mut Schema) { let mut implementation = RestrictFormatsImpl { infer_from_meta_schema: self.infer_from_meta_schema, inferred_formats: None, allowed_formats: &self.allowed_formats, }; implementation.transform(schema); } } static DEFINED_FORMATS: &[&str] = &[ // `duration` and `uuid` are defined only in draft 2019-09+ "duration", "uuid", // The rest are also defined in draft-07: "date-time", "date", "time", "email", "idn-email", "hostname", "idn-hostname", "ipv4", "ipv6", "uri", "uri-reference", "iri", "iri-reference", "uri-template", "json-pointer", "relative-json-pointer", "regex", ]; struct RestrictFormatsImpl<'a> { infer_from_meta_schema: bool, inferred_formats: Option<&'static [&'static str]>, allowed_formats: &'a BTreeSet>, } impl Transform for RestrictFormatsImpl<'_> { fn transform(&mut self, schema: &mut Schema) { let Some(obj) = schema.as_object_mut() else { return; }; let previous_inferred_formats = self.inferred_formats; if self.infer_from_meta_schema && obj.contains_key("$schema") { self.inferred_formats = match obj .get("$schema") .and_then(Value::as_str) .unwrap_or_default() { meta_schemas::DRAFT07 => Some(&DEFINED_FORMATS[2..]), meta_schemas::DRAFT2019_09 | meta_schemas::DRAFT2020_12 => Some(DEFINED_FORMATS), _ => { // we can't handle an unrecognised meta-schema return; } }; } if let Some(format) = obj.get("format").and_then(Value::as_str) { if !self.allowed_formats.contains(format) && !self .inferred_formats .is_some_and(|formats| formats.contains(&format)) { obj.remove("format"); } } transform_subschemas(self, schema); self.inferred_formats = previous_inferred_formats; } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn restrict_formats() { let mut schema = json_schema!({ "$schema": meta_schemas::DRAFT2020_12, "anyOf": [ { "format": "uuid" }, { "$schema": meta_schemas::DRAFT07, "format": "uuid" }, { "$schema": "http://unknown", "format": "uuid" }, { "format": "date" }, { "$schema": meta_schemas::DRAFT07, "format": "date" }, { "$schema": "http://unknown", "format": "date" }, { "format": "custom1" }, { "$schema": meta_schemas::DRAFT07, "format": "custom1" }, { "$schema": "http://unknown", "format": "custom1" }, { "format": "custom2" }, { "$schema": meta_schemas::DRAFT07, "format": "custom2" }, { "$schema": "http://unknown", "format": "custom2" }, ] }); let mut transform = RestrictFormats::default(); transform.allowed_formats.insert("custom1".into()); transform.transform(&mut schema); assert_eq!( schema, json_schema!({ "$schema": meta_schemas::DRAFT2020_12, "anyOf": [ { "format": "uuid" }, { "$schema": meta_schemas::DRAFT07 }, { "$schema": "http://unknown", "format": "uuid" }, { "format": "date" }, { "$schema": meta_schemas::DRAFT07, "format": "date" }, { "$schema": "http://unknown", "format": "date" }, { "format": "custom1" }, { "$schema": meta_schemas::DRAFT07, "format": "custom1" }, { "$schema": "http://unknown", "format": "custom1" }, { }, { "$schema": meta_schemas::DRAFT07 }, { "$schema": "http://unknown", "format": "custom2" }, ] }) ); } } schemars-1.2.1/tests/integration/arrayvec.rs000064400000000000000000000022051046102023000173000ustar 00000000000000use crate::prelude::*; use arrayvec07::{ArrayString, ArrayVec}; #[test] fn arrayvec07() { test!(ArrayVec) .assert_snapshot() .assert_allows_ser_roundtrip([ ArrayVec::from_iter([]), ArrayVec::from_iter([1, 2, 3, 4, 5, 6, 7, 8]), ]) .assert_matches_de_roundtrip( (0..16).map(|len| Value::Array((0..len).map(Value::from).collect())), ) .assert_matches_de_roundtrip(arbitrary_values_except( is_array_of_u64, "FIXME schema allows out-of-range positive integers", )); } #[test] fn arrayvec07_arraystring() { test!(ArrayString<8>) .assert_identical::() .assert_allows_ser_roundtrip(["".try_into().unwrap(), "12345678".try_into().unwrap()]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "There's not a good way to express UTF-8 byte length in JSON schema, so schema ignores the ArrayString's capacity.", )); } fn is_array_of_u64(value: &Value) -> bool { value .as_array() .is_some_and(|a| a.iter().all(Value::is_u64)) } schemars-1.2.1/tests/integration/attr_order.rs000064400000000000000000000040571046102023000176400ustar 00000000000000use crate::prelude::*; use pretty_assertions::assert_eq; use schemars::Schema; use std::fmt::Write; // This test ensures that `extend` and `transform` attributes are applied after other attributes, // and transforms are applied in the order they are defined. #[derive(JsonSchema, Deserialize, Serialize)] #[schemars(transform = suffix_description, description = "[Overwritten]", extend("description" = "The enum", "suffix" = "..."))] #[serde(untagged)] enum Untagged { #[schemars(transform = suffix_description, description = "The variant", extend("suffix" = "?"))] A { #[schemars(transform = suffix_description, description = "The field", extend("suffix" = "!"))] #[schemars(range(min = 1), transform = remove_minimum_and_default)] #[serde(default)] i: i32, }, } fn suffix_description(schema: &mut Schema) { let minimum = schema.get("minimum").map(Value::to_string); let Some(Value::String(suffix)) = schema.remove("suffix") else { panic!("expected `suffix` to be present and a string"); }; let Some(Value::String(description)) = schema.get_mut("description") else { panic!("expected `description` to be present and a string"); }; description.push_str(&suffix); if let Some(minimum) = minimum { write!(description, " (At least {})", minimum).unwrap(); } } fn remove_minimum_and_default(schema: &mut Schema) { schema.remove("minimum"); schema.remove("default"); } #[test] fn attributes_applied_in_order() { test!(Untagged).assert_snapshot().custom(|schema, _| { assert_eq!(schema.pointer("/description"), Some(&json!("The enum..."))); assert_eq!( schema.pointer("/anyOf/0/description"), Some(&json!("The variant?")) ); assert_eq!( schema.pointer("/anyOf/0/properties/i/description"), Some(&json!("The field! (At least 1)")) ); assert_eq!(schema.pointer("/anyOf/0/properties/i/default"), None); assert_eq!(schema.pointer("/anyOf/0/properties/i/minimum"), None); }); } schemars-1.2.1/tests/integration/bound.rs000064400000000000000000000043421046102023000165770ustar 00000000000000use crate::prelude::*; use std::marker::PhantomData; #[derive(Default)] struct MyIterator; impl Iterator for MyIterator { type Item = String; fn next(&mut self) -> Option { unimplemented!() } } // The default trait bounds would require T/U to implement JsonSchema, which MyIterator does not. #[derive(JsonSchema, Serialize, Deserialize, Default)] #[schemars(bound = "T::Item: JsonSchema")] pub struct MyContainer where T: Iterator, U: Iterator, { pub associated: T::Item, #[schemars(bound = "U::Item: JsonSchema")] pub associated2: U::Item, pub phantom: PhantomData, #[serde(skip)] pub _skipped: T, } #[test] fn manual_bound_set() { test!(MyContainer) // TODO with better bounds, this assertion would work: // .assert_identical::>>() .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_allows_ser_roundtrip([MyContainer { associated: "test".to_owned(), associated2: "test".to_owned(), phantom: PhantomData, _skipped: MyIterator, }]) .assert_matches_de_roundtrip(arbitrary_values()); assert_ne!( >::schema_id(), , MyIterator>>::schema_id() ); assert_ne!( >::schema_id(), >>::schema_id() ); } // `T` doesn't need to impl `JsonSchema`, but `U` does #[derive(JsonSchema, Serialize, Deserialize, Default)] pub struct MyContainer2 where T: Iterator, { pub u: Option, pub phantom: PhantomData, #[serde(skip)] pub _skipped: T, } #[test] fn auto_bound() { test!(MyContainer2) .assert_identical::, Box>>() .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_allows_ser_roundtrip([MyContainer2 { u: Some("test".to_owned()), phantom: PhantomData, _skipped: MyIterator, }]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/bytes.rs000064400000000000000000000005221046102023000166120ustar 00000000000000use crate::prelude::*; use bytes1::{Bytes, BytesMut}; #[test] fn bytes() { test!(Bytes) .assert_snapshot() .assert_allows_ser_roundtrip([Bytes::new(), Bytes::from_iter([12; 34])]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn bytes_mut() { test!(BytesMut).assert_identical::(); } schemars-1.2.1/tests/integration/chrono.rs000064400000000000000000000040431046102023000167560ustar 00000000000000use crate::prelude::*; use chrono04::{prelude::*, TimeDelta}; #[derive(JsonSchema, Serialize, Deserialize)] struct ChronoTypes { weekday: Weekday, date_time: DateTime, naive_date: NaiveDate, naive_date_time: NaiveDateTime, naive_time: NaiveTime, time_delta: TimeDelta, } #[test] fn chrono() { test!(ChronoTypes).assert_snapshot(); test!(Weekday) .assert_allows_ser_roundtrip([Weekday::Mon]) .assert_matches_de_roundtrip(arbitrary_values()); test!(DateTime) .assert_allows_ser_roundtrip_default() // JSON Schema only allows dates with 4-digit years // .assert_allows_ser_roundtrip([DateTime::::MIN_UTC, DateTime::::MAX_UTC]) .assert_matches_de_roundtrip(arbitrary_values()); test!(NaiveDate) .assert_allows_ser_roundtrip_default() // JSON Schema only allows dates with 4-digit years // .assert_allows_ser_roundtrip([NaiveDate::MIN, NaiveDate::MAX]) .assert_matches_de_roundtrip(arbitrary_values()); test!(NaiveDateTime) .assert_allows_ser_roundtrip_default() // JSON Schema only allows dates with 4-digit years // .assert_allows_ser_roundtrip([NaiveDateTime::MIN, NaiveDateTime::MAX]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'partial-date-time', so arbitrary strings technically allowed by schema", )); test!(NaiveTime) .assert_allows_ser_roundtrip_default() .assert_allows_ser_roundtrip([NaiveTime::MIN, NaiveDateTime::MAX.time()]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'date-time', so arbitrary strings technically allowed by schema", )); test!(TimeDelta) .assert_allows_ser_roundtrip_default() .assert_allows_ser_roundtrip([TimeDelta::MIN, TimeDelta::MAX]) .assert_rejects_de([json!([0, -1]), json!([0, 1_000_000_000])]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/contract.rs000064400000000000000000000207001046102023000173010ustar 00000000000000use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize)] #[serde(rename_all(serialize = "SCREAMING-KEBAB-CASE"), deny_unknown_fields)] struct StructDenyUnknownFields { #[serde(skip_deserializing)] read_only: bool, #[allow(dead_code)] #[serde(skip_serializing)] write_only: bool, #[serde(default)] default: bool, #[serde(skip_serializing_if = "core::ops::Not::not")] skip_serializing_if: bool, #[serde(rename(serialize = "ser_renamed", deserialize = "de_renamed"))] renamed: bool, option: Option, } #[derive(JsonSchema, Deserialize, Serialize)] struct StructAllowUnknownFields { #[serde(flatten)] inner: StructDenyUnknownFields, } #[test] fn struct_deny_unknown_fields() { test!(StructDenyUnknownFields) .assert_snapshot() .assert_allows_de_roundtrip([ json!({ "write_only": false, "skip_serializing_if": false, "de_renamed": false }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "default": true }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "option": true }), ]) .assert_rejects_de([ json!({ "skip_serializing_if": false, "de_renamed": false }), json!({ "write_only": false, "de_renamed": false }), json!({ "write_only": false, "skip_serializing_if": false }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "unknown": true }), ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn struct_allow_unknown_fields() { test!(StructAllowUnknownFields) .assert_snapshot() .assert_allows_de_roundtrip([ json!({ "write_only": false, "skip_serializing_if": false, "de_renamed": false }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "default": true }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "option": true }), json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "unknown": true }), ]) .assert_rejects_de([ json!({ "skip_serializing_if": false, "de_renamed": false }), json!({ "write_only": false, "de_renamed": false }), json!({ "write_only": false, "skip_serializing_if": false }), ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] struct TupleStruct( String, #[allow(dead_code)] #[serde(skip_serializing)] bool, String, #[serde(skip_deserializing)] bool, String, ); #[test] fn tuple_struct() { test!(TupleStruct) .assert_snapshot() .assert_allows_de_roundtrip([json!(["", true, "", ""])]) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] #[serde( rename_all(serialize = "SCREAMING-KEBAB-CASE"), rename_all_fields(serialize = "PascalCase") )] enum ExternalEnum { #[serde(skip_deserializing)] ReadOnlyUnit, #[serde(skip_serializing)] WriteOnlyUnit, #[serde(skip_deserializing)] ReadOnlyStruct { s: String }, #[serde(skip_serializing)] WriteOnlyStruct { i: isize }, #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] RenamedUnit, #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] RenamedStruct { b: bool }, } #[test] fn externally_tagged_enum() { test!(ExternalEnum) .assert_snapshot() .assert_allows_ser_roundtrip([ ExternalEnum::ReadOnlyUnit, ExternalEnum::ReadOnlyStruct { s: "test".into() }, ExternalEnum::RenamedUnit, ExternalEnum::RenamedStruct { b: true }, ]) .assert_allows_de_roundtrip([ json!("WriteOnlyUnit"), json!({ "WriteOnlyStruct": { "i": 123 } }), json!("de_renamed_unit"), json!({ "de_renamed_struct": { "b": true } }), ]) .assert_rejects_de([ json!("READ-ONLY-UNIT"), json!("ReadOnlyUnit"), json!("ser_renamed_unit"), ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] #[serde( tag = "tag", rename_all(serialize = "SCREAMING-KEBAB-CASE"), rename_all_fields(serialize = "PascalCase") )] enum InternalEnum { #[serde(skip_deserializing)] ReadOnlyUnit, #[serde(skip_serializing)] WriteOnlyUnit, #[serde(skip_deserializing)] ReadOnlyStruct { s: String }, #[serde(skip_serializing)] WriteOnlyStruct { i: isize }, #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] RenamedUnit, #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] RenamedStruct { b: bool }, } #[test] fn internally_tagged_enum() { test!(InternalEnum) .assert_snapshot() .assert_allows_ser_roundtrip([ InternalEnum::ReadOnlyUnit, InternalEnum::ReadOnlyStruct { s: "test".into() }, InternalEnum::RenamedUnit, InternalEnum::RenamedStruct { b: true }, ]) .assert_allows_de_roundtrip([ json!({ "tag": "WriteOnlyUnit" }), json!({ "tag": "WriteOnlyStruct", "i": 123 }), json!({ "tag": "de_renamed_unit" }), json!({ "tag": "de_renamed_struct", "b": true }), ]) .assert_rejects_de([ json!({ "tag": "READ-ONLY-UNIT" }), json!({ "tag": "ReadOnlyUnit" }), json!({ "tag": "ser_renamed_unit" }), ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] #[serde( tag = "tag", content = "content", rename_all(serialize = "SCREAMING-KEBAB-CASE"), rename_all_fields(serialize = "PascalCase") )] enum AdjacentEnum { #[serde(skip_deserializing)] ReadOnlyUnit, #[serde(skip_serializing)] WriteOnlyUnit, #[serde(skip_deserializing)] ReadOnlyStruct { s: String }, #[serde(skip_serializing)] WriteOnlyStruct { i: isize }, #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] RenamedUnit, #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] RenamedStruct { b: bool }, } #[test] fn adjacently_tagged_enum() { test!(AdjacentEnum) .assert_snapshot() .assert_allows_ser_roundtrip([ AdjacentEnum::ReadOnlyUnit, AdjacentEnum::ReadOnlyStruct { s: "test".into() }, AdjacentEnum::RenamedUnit, AdjacentEnum::RenamedStruct { b: true }, ]) .assert_allows_de_roundtrip([ json!({ "tag": "WriteOnlyUnit" }), json!({ "tag": "WriteOnlyStruct", "content": { "i": 123 } }), json!({ "tag": "de_renamed_unit" }), json!({ "tag": "de_renamed_struct", "content": { "b": true } }), ]) .assert_rejects_de([ json!({ "tag": "READ-ONLY-UNIT" }), json!({ "tag": "ReadOnlyUnit" }), json!({ "tag": "ser_renamed_unit" }), ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] #[serde( untagged, rename_all(serialize = "SCREAMING-KEBAB-CASE"), rename_all_fields(serialize = "PascalCase") )] enum UntaggedEnum { #[serde(skip_deserializing)] ReadOnlyUnit, #[serde(skip_serializing)] WriteOnlyUnit, #[serde(skip_deserializing)] ReadOnlyStruct { s: String }, #[serde(skip_serializing)] WriteOnlyStruct { i: isize }, #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] RenamedUnit, #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] RenamedStruct { b: bool }, } #[test] fn untagged_enum() { test!(UntaggedEnum) .assert_snapshot() .assert_allows_ser_roundtrip([ UntaggedEnum::ReadOnlyUnit, UntaggedEnum::ReadOnlyStruct { s: "test".into() }, UntaggedEnum::RenamedUnit, UntaggedEnum::RenamedStruct { b: true }, ]) .assert_allows_de_roundtrip([json!(null), json!({ "i": 123 }), json!({ "b": true })]) .assert_rejects_de([json!({ "s": "test" })]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/crate_alias.rs000064400000000000000000000007521046102023000177400ustar 00000000000000use crate::prelude::*; use ::schemars as aliased_schemars; #[allow(dead_code)] #[derive(aliased_schemars::JsonSchema, Deserialize, Serialize, Default)] #[schemars(crate = "aliased_schemars")] struct MyStruct { /// Is it ok with doc comments? foo: i32, #[schemars(extend("x-test" = "...and extensions?"))] bar: bool, } #[test] fn crate_alias() { test!(MyStruct) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/decimal.rs000064400000000000000000000011511046102023000170610ustar 00000000000000use crate::prelude::*; #[test] fn decimal_types() { #[cfg(feature = "rust_decimal1")] test!(rust_decimal1::Decimal) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); #[cfg(feature = "bigdecimal04")] test!(bigdecimal04::BigDecimal) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); #[cfg(all(feature = "rust_decimal1", feature = "bigdecimal04"))] test!(bigdecimal04::BigDecimal).assert_identical::(); } schemars-1.2.1/tests/integration/default.rs000064400000000000000000000047701046102023000171210ustar 00000000000000use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(default)] struct MyStruct { integer: u32, boolean: bool, option_string: Option, #[serde(skip_serializing_if = "str::is_empty")] string_skip_empty: String, #[serde(with = "struct_2_as_str")] #[schemars(with = "str", pattern(r"^\d+ (true|false)$"))] struct2: MyStruct2, #[serde(skip_serializing)] not_serialize: NotSerialize, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(default = "ten_and_true")] struct MyStruct2 { #[serde(default = "six")] integer: u32, boolean: bool, } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Default)] struct NotSerialize(i8); mod struct_2_as_str { use super::MyStruct2; pub(super) fn serialize(value: &MyStruct2, ser: S) -> Result where S: serde::Serializer, { ser.collect_str(&format_args!("{} {}", value.integer, value.boolean)) } pub(super) fn deserialize<'de, D>(deser: D) -> Result where D: serde::Deserializer<'de>, { use serde::de::{Deserialize, Error}; let error = || Error::custom("invalid string"); let (i, b) = <&str>::deserialize(deser)? .split_once(' ') .ok_or_else(error)?; Ok(MyStruct2 { integer: i.parse().map_err(|_| error())?, boolean: b.parse().map_err(|_| error())?, }) } } fn ten_and_true() -> MyStruct2 { MyStruct2 { integer: 10, boolean: true, } } fn six() -> u32 { 6 } #[test] fn default_fields() { test!(MyStruct) .assert_snapshot() .assert_allows_ser_roundtrip([ MyStruct::default(), MyStruct { integer: 123, boolean: true, option_string: Some("test".into()), string_skip_empty: "test".into(), struct2: ten_and_true(), not_serialize: NotSerialize(42), }, ]) .assert_allows_de_roundtrip([ json!({}), json!({ "not_serialize": 127 }) ]) .assert_rejects_de([ json!({ "not_serialize": "a string" }) ]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); } schemars-1.2.1/tests/integration/deprecated.rs000064400000000000000000000034451046102023000175730ustar 00000000000000#![allow(deprecated)] use crate::prelude::*; use pretty_assertions::assert_eq; #[derive(JsonSchema, Default, Serialize, Deserialize)] #[deprecated] struct DeprecatedStruct { foo: i32, #[deprecated] bar: bool, } #[allow(deprecated)] #[test] fn deprecated_struct() { test!(DeprecatedStruct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .custom(|schema, _| { assert_eq!( schema.as_value().pointer("/deprecated"), Some(&Value::Bool(true)), ); assert_eq!( schema.as_value().pointer("/properties/bar/deprecated"), Some(&Value::Bool(true)), ); }); } #[derive(JsonSchema, Default, Serialize, Deserialize)] #[deprecated] enum DeprecatedEnum { #[default] Unit, #[deprecated] DeprecatedUnitVariant, #[deprecated] DeprecatedStructVariant { foo: i32, #[deprecated] deprecated_field: bool, }, } #[test] fn deprecated_enum() { test!(DeprecatedEnum) .assert_snapshot() .assert_allows_ser_roundtrip_default() .custom(|schema, _| { assert_eq!( schema.as_value().pointer("/deprecated"), Some(&Value::Bool(true)), ); assert_eq!( schema.as_value().pointer("/oneOf/1/deprecated"), Some(&Value::Bool(true)), ); assert_eq!( schema.as_value().pointer("/oneOf/2/deprecated"), Some(&Value::Bool(true)), ); assert_eq!( schema.as_value().pointer("/oneOf/2/properties/DeprecatedStructVariant/properties/deprecated_field/deprecated"), Some(&Value::Bool(true)), ); }); } schemars-1.2.1/tests/integration/docs.rs000064400000000000000000000035711046102023000164230ustar 00000000000000use crate::prelude::*; #[allow(dead_code)] #[derive(JsonSchema)] /** # This is the struct's title This is the struct's description. */ struct MyStruct { /// # An integer my_int: i32, my_undocumented_bool: bool, /// A unit struct instance my_unit: MyUnitStruct, #[doc = concat!("# Documented ", "bool")] #[doc = concat!("This bool is documented")] my_documented_bool: bool, } /// # A Unit #[derive(JsonSchema)] struct MyUnitStruct; #[test] fn doc_comments_struct() { test!(MyStruct).assert_snapshot(); } #[allow(dead_code)] #[doc = " # This is the enum's title "] #[doc = " This is "] #[derive(JsonSchema)] #[doc = " the enum's description."] enum MyEnum { UndocumentedUnit, UndocumentedUnit2, /// This comment is included in the generated schema :) DocumentedUnit, /// ## Complex variant /// This is a struct-like variant. Complex { /// ### A nullable string /// /// This field is a nullable string. /// /// This ///is /// the second /// line! /// /// /// /// /// And this is the third! my_nullable_string: Option, }, } #[test] fn doc_comments_enum() { test!(MyEnum).assert_snapshot(); } /// # OverrideDocs struct /// This description should be overridden #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(description = "New description")] struct OverrideDocs { /// # Overridden #[schemars(title = "My integer", description = "This is an i32")] my_int: i32, /// # Overridden /// Also overridden #[schemars(title = "", description = "")] my_undocumented_bool: bool, #[schemars(title = concat!("Documented ", "bool"), description = "Capitalized".to_uppercase())] my_documented_bool: bool, } #[test] fn doc_comments_override() { test!(OverrideDocs).assert_snapshot(); } schemars-1.2.1/tests/integration/either.rs000064400000000000000000000005611046102023000167470ustar 00000000000000use crate::prelude::*; use either1::Either; #[test] fn either() { test!(Either>) .assert_snapshot() .assert_allows_ser_roundtrip([ Either::Left(123), Either::Right(Either::Left(true)), Either::Right(Either::Right(())), ]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/enum_repr.rs000064400000000000000000000016561046102023000174710ustar 00000000000000use crate::prelude::*; use schemars::JsonSchema_repr; use serde_repr::{Deserialize_repr, Serialize_repr}; #[derive(JsonSchema_repr, Deserialize_repr, Serialize_repr)] #[repr(u8)] #[serde(rename = "EnumWithReprAttr")] /// Description from comment pub enum Enum { Zero, One, Five = 5, Six, Three = 3, } #[test] fn enum_repr() { test!(Enum) .assert_snapshot() .assert_allows_ser_roundtrip([Enum::Zero, Enum::One, Enum::Five, Enum::Six, Enum::Three]) .assert_allows_de_roundtrip([ Value::from(0), Value::from(1), Value::from(5), Value::from(6), Value::from(3), ]) .assert_rejects_de([ Value::from("Zero"), Value::from("One"), Value::from("Five"), Value::from("Six"), Value::from("Three"), ]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/enums.rs000064400000000000000000000241411046102023000166160ustar 00000000000000use crate::prelude::*; use pretty_assertions::assert_eq; use schemars::generate::SchemaSettings; use std::collections::BTreeMap; #[derive(JsonSchema, Deserialize, Serialize)] struct UnitStruct; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { foo: i32, bar: bool, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] enum External { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, EmptyTuple(), Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl External { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, // Ignored due to https://github.com/serde-rs/json/issues/1084 // Self::EmptyTuple(), Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag")] enum Internal { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool }, // Internally-tagged enums don't support tuple variants // EmptyTuple(), // Tuple(i32, bool), UnitTwo, // Internally-tagged enum variants don't support non-object "payloads" // #[serde(with = "unit_variant_as_u64")] // #[schemars(with = "u64")] // UnitAsInt, // Internally-tagged enums don't support tuple variants // #[serde(with = "tuple_variant_as_str")] // #[schemars(schema_with = "tuple_variant_as_str::json_schema")] // TupleAsStr(i32, bool), } impl Internal { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, // Self::EmptyTuple(), // Self::Tuple(456, false), Self::UnitTwo, // Self::UnitAsInt, // Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag", content = "content")] enum Adjacent { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, EmptyTuple(), Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl Adjacent { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, Self::EmptyTuple(), Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged)] enum Untagged { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, EmptyTuple(), Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl Untagged { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, Self::EmptyTuple(), Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } mod unit_variant_as_u64 { pub(super) fn serialize(ser: S) -> Result where S: serde::Serializer, { ser.serialize_u64(42) } pub(super) fn deserialize<'de, D>(deser: D) -> Result<(), D::Error> where D: serde::Deserializer<'de>, { use serde::de::Deserialize; u64::deserialize(deser).map(|_| ()) } } mod tuple_variant_as_str { pub(super) fn serialize(i: &i32, b: &bool, ser: S) -> Result where S: serde::Serializer, { ser.collect_str(&format_args!("{i} {b}")) } pub(super) fn deserialize<'de, D>(deser: D) -> Result<(i32, bool), D::Error> where D: serde::Deserializer<'de>, { use serde::de::{Deserialize, Error}; let error = || Error::custom("invalid string"); let (i, b) = <&str>::deserialize(deser)? .split_once(' ') .ok_or_else(error)?; Ok(( i.parse().map_err(|_| error())?, b.parse().map_err(|_| error())?, )) } pub(super) fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { schemars::json_schema!({ "type": "string", "pattern": r"^\d+ (true|false)$" }) } } #[test] fn externally_tagged_enum() { test!(External) .assert_snapshot() .assert_allows_ser_roundtrip(External::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn internally_tagged_enum() { test!(Internal) .assert_snapshot() .assert_allows_ser_roundtrip(Internal::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn adjacently_tagged_enum() { test!(Adjacent) .assert_snapshot() .assert_allows_ser_roundtrip(Adjacent::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn untagged_enum() { test!(Untagged) .assert_snapshot() .assert_allows_ser_roundtrip(Untagged::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn untagged_enum_with_titles() { test!( Untagged, SchemaSettings::default().with(|s| s.untagged_enum_variant_titles = true) ) .custom(|s, _| { assert_eq!( s.pointer("/anyOf/0/title").and_then(Value::as_str), Some("UnitOne") ); for variant in s.pointer("/anyOf").and_then(Value::as_array).unwrap() { assert!(variant.get("title").is_some_and(Value::is_string)); } }) .assert_snapshot() .assert_allows_ser_roundtrip(Untagged::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Serialize, Deserialize)] enum NoVariants {} #[test] fn no_variants() { test!(NoVariants) .assert_snapshot() .assert_rejects_de(arbitrary_values()); } #[derive(JsonSchema, Serialize, Deserialize)] #[serde(rename_all_fields = "UPPERCASE", rename_all = "snake_case")] enum Renamed { StructVariant { field: String, }, #[serde(rename = "custom name variant")] RenamedStructVariant { #[serde(rename = "custom name field")] field: String, }, } #[test] fn renamed() { test!(Renamed) .assert_snapshot() .assert_allows_ser_roundtrip([ Renamed::StructVariant { field: "foo".to_owned(), }, Renamed::RenamedStructVariant { field: "bar".to_owned(), }, ]) .assert_rejects_de(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] enum SoundOfMusic { /// # A deer /// /// A female deer Do, /// A drop of golden sun Re, /// A name I call myself Mi, } #[test] fn unit_variants_with_doc_comments() { test!(SoundOfMusic) .assert_snapshot() .assert_allows_ser_roundtrip([SoundOfMusic::Do, SoundOfMusic::Re, SoundOfMusic::Mi]) .assert_rejects_de(arbitrary_values()) .custom(|schema, _| { assert_eq!( schema.as_value().pointer("/oneOf/0/title"), Some(&("A deer".into())), ); assert_eq!( schema.as_value().pointer("/oneOf/0/description"), Some(&("A female deer".into())), ); assert_eq!( schema.as_value().pointer("/oneOf/1/description"), Some(&("A drop of golden sun".into())), ); assert_eq!( schema.as_value().pointer("/oneOf/2/description"), Some(&("A name I call myself".into())), ); }); } schemars-1.2.1/tests/integration/enums_deny_unknown_fields.rs000064400000000000000000000122641046102023000227450ustar 00000000000000use crate::prelude::*; use std::collections::BTreeMap; macro_rules! fn_values { () => { fn values() -> impl IntoIterator { [ Self::Unit, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::StructDenyUnknownFieldsNewType(StructDenyUnknownFields { baz: 123, foobar: true, }), Self::Struct { foo: 123, bar: true, }, ] } }; } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { foo: i32, bar: bool, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(deny_unknown_fields)] struct StructDenyUnknownFields { baz: i32, foobar: bool, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(deny_unknown_fields)] enum External { Unit, StringMap(BTreeMap), StructNewType(Struct), StructDenyUnknownFieldsNewType(StructDenyUnknownFields), Struct { foo: i32, bar: bool }, } impl External { fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag", deny_unknown_fields)] enum Internal { Unit, StringMap(BTreeMap), StructNewType(Struct), StructDenyUnknownFieldsNewType(StructDenyUnknownFields), Struct { foo: i32, bar: bool }, } impl Internal { fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag", content = "content", deny_unknown_fields)] enum Adjacent { Unit, StringMap(BTreeMap), StructNewType(Struct), StructDenyUnknownFieldsNewType(StructDenyUnknownFields), Struct { foo: i32, bar: bool }, } impl Adjacent { fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged, deny_unknown_fields)] enum Untagged { Unit, StringMap(BTreeMap), StructNewType(Struct), StructDenyUnknownFieldsNewType(StructDenyUnknownFields), Struct { foo: i32, bar: bool }, } impl Untagged { fn_values!(); } #[test] fn externally_tagged_enum() { test!(External) .assert_snapshot() .assert_allows_ser_roundtrip(External::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([ json!({ "Struct": { "foo": 123, "bar": true, "extra": null } }), json!({ "StructDenyUnknownFieldsNewType": { "baz": 123, "foobar": true, "extra": null } }), ]) .assert_allows_de_roundtrip([json!({ "StructNewType": { "foo": 123, "bar": true, "extra": null } })]); } #[test] fn internally_tagged_enum() { test!(Internal) .assert_snapshot() .assert_allows_ser_roundtrip(Internal::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([ json!({ "tag": "Struct", "foo": 123, "bar": true, "extra": null }), json!({ "tag": "StructDenyUnknownFieldsNewType", "baz": 123, "foobar": true, "extra": null }), ]) .assert_allows_de_roundtrip([json!({ "tag": "StructNewType", "foo": 123, "bar": true, "extra": null })]); } #[test] fn adjacently_tagged_enum() { test!(Adjacent) .assert_snapshot() .assert_allows_ser_roundtrip(Adjacent::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([ json!({ "tag": "Struct", "content": { "foo": 123, "bar": true, "extra": null } }), json!({ "tag": "StructDenyUnknownFieldsNewType", "content": { "baz": 123, "foobar": true, "extra": null } }), ]) .assert_allows_de_roundtrip([json!({ "tag": "StructNewType", "content": { "foo": 123, "bar": true, "extra": null } })]); } #[test] fn untagged_enum() { test!(Untagged) .assert_snapshot() .assert_allows_ser_roundtrip(Untagged::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([json!({ "baz": 123, "foobar": true, "extra": null })]) .assert_allows_de_roundtrip([json!({ "foo": 123, "bar": true, "extra": null })]); } schemars-1.2.1/tests/integration/enums_flattened.rs000064400000000000000000000210041046102023000206370ustar 00000000000000use crate::prelude::*; use schemars::generate::SchemaSettings; #[derive(JsonSchema, Deserialize, Serialize)] struct EmptyStruct {} #[derive(JsonSchema, Deserialize, Serialize)] enum External1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] enum External2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] enum External3 { Int(u32), Tuple(u8, bool), } #[derive(JsonSchema, Deserialize, Serialize)] enum External4 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct ExternalContainer { f: f32, #[serde(flatten)] e1: External1, #[serde(flatten)] e2: External2, #[serde(flatten)] e3: External3, #[serde(flatten)] e4: External4, } impl ExternalContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: External1::Unit1, e2: External2::Unit3, e3: External3::Int(123), e4: External4::StructNewType(EmptyStruct {}), }, Self { f: 9.87, e1: External1::Unit2, e2: External2::ValueNewType(json!({"key": "value"})), e3: External3::Tuple(0, true), e4: External4::Struct { foo: 1, bar: true }, }, ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct ExternalContainerDenyUnknownFields { f: f32, #[serde(flatten)] e1: External1, #[serde(flatten)] e2: External2, #[serde(flatten)] e3: External3, #[serde(flatten)] e4: External4, } impl ExternalContainerDenyUnknownFields { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: External1::Unit1, e2: External2::Unit3, e3: External3::Int(123), e4: External4::StructNewType(EmptyStruct {}), }, Self { f: 9.87, e1: External1::Unit2, e2: External2::ValueNewType(json!({"key": "value"})), e3: External3::Tuple(0, true), e4: External4::Struct { foo: 1, bar: true }, }, ] } } fn external_container_json_with_extra_field() -> Value { json!({ "f": 1.23, "Unit1": null, "Unit3": null, "Int": 123, "StructNewType": {}, "extra": null }) } #[test] fn external_enums_flattened() { test!(ExternalContainer) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_allows_de_roundtrip([external_container_json_with_extra_field()]); } #[test] fn external_enums_flattened_deny_unknown_fields() { test!(ExternalContainerDenyUnknownFields) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([external_container_json_with_extra_field()]); } #[test] fn external_enums_flattened_deny_unknown_fields_draft07() { test!( ExternalContainerDenyUnknownFields, SchemaSettings::draft07() ) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([external_container_json_with_extra_field()]); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag1")] enum Internal1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag2")] enum Internal2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag3")] enum Internal3 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct InternalContainer { f: f32, #[serde(flatten)] e1: Internal1, #[serde(flatten)] e2: Internal2, #[serde(flatten)] e3: Internal3, } impl InternalContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Internal1::Unit1, e2: Internal2::Unit3, e3: Internal3::StructNewType(EmptyStruct {}), }, Self { f: 9.87, e1: Internal1::Unit2, e2: Internal2::ValueNewType(json!({"key": "value"})), e3: Internal3::Struct { foo: 1, bar: true }, }, ] } } #[test] fn internal_enums_flattened() { test!(InternalContainer) .assert_snapshot() .assert_allows_ser_roundtrip(InternalContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag1", content = "content1")] enum Adjacent1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag2", content = "content2")] enum Adjacent2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag3", content = "content3")] enum Adjacent3 { Int(u32), Tuple(u8, bool), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag4", content = "content4")] enum Adjacent4 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct AdjacentContainer { f: f32, #[serde(flatten)] e1: Adjacent1, #[serde(flatten)] e2: Adjacent2, #[serde(flatten)] e3: Adjacent3, #[serde(flatten)] e4: Adjacent4, } impl AdjacentContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Adjacent1::Unit1, e2: Adjacent2::Unit3, e3: Adjacent3::Int(123), e4: Adjacent4::StructNewType(EmptyStruct {}), }, Self { f: 9.87, e1: Adjacent1::Unit2, e2: Adjacent2::ValueNewType(json!({"key": "value"})), e3: Adjacent3::Tuple(0, true), e4: Adjacent4::Struct { foo: 1, bar: true }, }, ] } } #[test] fn adjacent_enums_flattened() { test!(AdjacentContainer) .assert_snapshot() .assert_allows_ser_roundtrip(AdjacentContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged)] enum Untagged { Struct1 { foo: i32 }, Struct2 { bar: bool }, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] struct UntaggedContainer { f: f32, #[serde(flatten)] e1: Untagged, } impl UntaggedContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Untagged::Struct1 { foo: 1 }, }, Self { f: 9.87, e1: Untagged::Struct2 { bar: true }, }, Self { f: 42.0, e1: Untagged::ValueNewType(json!({"key": "value"})), }, ] } } #[test] fn untagged_enums_flattened() { test!(UntaggedContainer) .assert_snapshot() .assert_allows_ser_roundtrip(UntaggedContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] struct MixedContainer { f: f32, #[serde(flatten)] e1: External1, #[serde(flatten)] i2: Internal2, #[serde(flatten)] a3: Adjacent3, #[serde(flatten)] u: Untagged, } impl MixedContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: External1::Unit1, i2: Internal2::Unit3, a3: Adjacent3::Int(123), u: Untagged::Struct1 { foo: 1 }, }, Self { f: 9.87, e1: External1::Unit2, i2: Internal2::ValueNewType(json!({"key": "value"})), a3: Adjacent3::Tuple(0, true), u: Untagged::ValueNewType(json!({"key": "value"})), }, ] } } #[test] fn mixed_enums_flattened() { test!(MixedContainer) .assert_snapshot() .assert_allows_ser_roundtrip(MixedContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/enums_option_flattened.rs000064400000000000000000000233261046102023000222400ustar 00000000000000use crate::prelude::*; use schemars::generate::SchemaSettings; #[derive(JsonSchema, Deserialize, Serialize)] struct EmptyStruct {} #[derive(JsonSchema, Deserialize, Serialize)] enum External1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] enum External2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] enum External3 { Int(u32), Tuple(u8, bool), } #[derive(JsonSchema, Deserialize, Serialize)] enum External4 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct ExternalContainer { f: f32, #[serde(flatten)] e1: Option, #[serde(flatten)] e2: Option, #[serde(flatten)] e3: Option, #[serde(flatten)] e4: Option, } impl ExternalContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(External1::Unit1), e2: Some(External2::Unit3), e3: Some(External3::Int(123)), e4: Some(External4::StructNewType(EmptyStruct {})), }, Self { f: 9.87, e1: Some(External1::Unit2), e2: Some(External2::ValueNewType(json!({"key": "value"}))), e3: Some(External3::Tuple(0, true)), e4: Some(External4::Struct { foo: 1, bar: true }), }, Self { f: 9.87, e1: None, e2: None, e3: None, e4: None, }, ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct ExternalContainerDenyUnknownFields { f: f32, #[serde(flatten)] e1: Option, #[serde(flatten)] e2: Option, #[serde(flatten)] e3: Option, #[serde(flatten)] e4: Option, } impl ExternalContainerDenyUnknownFields { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(External1::Unit1), e2: Some(External2::Unit3), e3: Some(External3::Int(123)), e4: Some(External4::StructNewType(EmptyStruct {})), }, Self { f: 9.87, e1: Some(External1::Unit2), e2: Some(External2::ValueNewType(json!({"key": "value"}))), e3: Some(External3::Tuple(0, true)), e4: Some(External4::Struct { foo: 1, bar: true }), }, Self { f: 9.87, e1: None, e2: None, e3: None, e4: None, }, ] } } fn external_container_json_with_extra_field() -> Value { json!({ "f": 1.23, "Unit1": null, "Unit3": null, "Int": 123, "StructNewType": {}, "extra": null }) } #[test] fn external_enums_flattened() { test!(ExternalContainer) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_allows_de_roundtrip([external_container_json_with_extra_field()]); } #[test] fn external_enums_flattened_deny_unknown_fields() { test!(ExternalContainerDenyUnknownFields) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([external_container_json_with_extra_field()]); } #[test] fn external_enums_flattened_deny_unknown_fields_draft07() { test!( ExternalContainerDenyUnknownFields, SchemaSettings::draft07() ) .assert_snapshot() .assert_allows_ser_roundtrip(ExternalContainerDenyUnknownFields::values()) .assert_matches_de_roundtrip(arbitrary_values()) .assert_rejects_de([external_container_json_with_extra_field()]); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag1")] enum Internal1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag2")] enum Internal2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag3")] enum Internal3 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct InternalContainer { f: f32, #[serde(flatten)] e1: Option, #[serde(flatten)] e2: Option, #[serde(flatten)] e3: Option, } impl InternalContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(Internal1::Unit1), e2: Some(Internal2::Unit3), e3: Some(Internal3::StructNewType(EmptyStruct {})), }, Self { f: 9.87, e1: Some(Internal1::Unit2), e2: Some(Internal2::ValueNewType(json!({"key": "value"}))), e3: Some(Internal3::Struct { foo: 1, bar: true }), }, Self { f: 9.87, e1: None, e2: None, e3: None, }, ] } } #[test] fn internal_enums_flattened() { test!(InternalContainer) .assert_snapshot() .assert_allows_ser_roundtrip(InternalContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag1", content = "content1")] enum Adjacent1 { Unit1, Unit2, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag2", content = "content2")] enum Adjacent2 { Unit3, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag3", content = "content3")] enum Adjacent3 { Int(u32), Tuple(u8, bool), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag4", content = "content4")] enum Adjacent4 { StructNewType(EmptyStruct), Struct { foo: i32, bar: bool }, } #[derive(JsonSchema, Deserialize, Serialize)] struct AdjacentContainer { f: f32, #[serde(flatten)] e1: Option, #[serde(flatten)] e2: Option, #[serde(flatten)] e3: Option, #[serde(flatten)] e4: Option, } impl AdjacentContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(Adjacent1::Unit1), e2: Some(Adjacent2::Unit3), e3: Some(Adjacent3::Int(123)), e4: Some(Adjacent4::StructNewType(EmptyStruct {})), }, Self { f: 9.87, e1: Some(Adjacent1::Unit2), e2: Some(Adjacent2::ValueNewType(json!({"key": "value"}))), e3: Some(Adjacent3::Tuple(0, true)), e4: Some(Adjacent4::Struct { foo: 1, bar: true }), }, Self { f: 9.87, e1: None, e2: None, e3: None, e4: None, }, ] } } #[test] fn adjacent_enums_flattened() { test!(AdjacentContainer) .assert_snapshot() .assert_allows_ser_roundtrip(AdjacentContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged)] enum Untagged { Struct1 { foo: i32 }, Struct2 { bar: bool }, ValueNewType(Value), } #[derive(JsonSchema, Deserialize, Serialize)] struct UntaggedContainer { f: f32, #[serde(flatten)] e1: Option, } impl UntaggedContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(Untagged::Struct1 { foo: 1 }), }, Self { f: 9.87, e1: Some(Untagged::Struct2 { bar: true }), }, Self { f: 42.0, e1: Some(Untagged::ValueNewType(json!({"key": "value"}))), }, Self { f: 42.0, e1: None }, ] } } #[test] fn untagged_enums_flattened() { test!(UntaggedContainer) .assert_snapshot() .assert_allows_ser_roundtrip(UntaggedContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] struct MixedContainer { f: f32, #[serde(flatten)] e1: Option, #[serde(flatten)] i2: Option, #[serde(flatten)] a3: Option, #[serde(flatten)] u: Option, } impl MixedContainer { fn values() -> impl IntoIterator { [ Self { f: 1.23, e1: Some(External1::Unit1), i2: Some(Internal2::Unit3), a3: Some(Adjacent3::Int(123)), u: Some(Untagged::Struct1 { foo: 1 }), }, Self { f: 9.87, e1: Some(External1::Unit2), i2: Some(Internal2::ValueNewType(json!({"key": "value"}))), a3: Some(Adjacent3::Tuple(0, true)), u: Some(Untagged::ValueNewType(json!({"key": "value"}))), }, Self { f: 9.87, e1: None, i2: None, a3: None, u: None, }, ] } } #[test] fn mixed_enums_flattened() { test!(MixedContainer) .assert_snapshot() .assert_allows_ser_roundtrip(MixedContainer::values()) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/enums_ref_variants.rs000064400000000000000000000204221046102023000213570ustar 00000000000000use crate::prelude::*; use std::collections::BTreeMap; #[derive(JsonSchema, Deserialize, Serialize)] struct UnitStruct; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { foo: i32, bar: bool, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[schemars(_unstable_ref_variants)] enum External { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl External { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag")] #[schemars(_unstable_ref_variants)] enum Internal { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool }, // Internally-tagged enums don't support tuple variants // Tuple(i32, bool), UnitTwo, // Internally-tagged enum variants don't support non-object "payloads" // #[serde(with = "unit_variant_as_u64")] // #[schemars(with = "u64")] // UnitAsInt, // Internally-tagged enums don't support tuple variants // #[serde(with = "tuple_variant_as_str")] // #[schemars(schema_with = "tuple_variant_as_str::json_schema")] // TupleAsStr(i32, bool), } impl Internal { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, // Self::Tuple(456, false), Self::UnitTwo, // Self::UnitAsInt, // Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag", content = "content")] #[schemars(_unstable_ref_variants)] enum Adjacent { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl Adjacent { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged)] #[schemars(_unstable_ref_variants)] enum Untagged { UnitOne, StringMap(BTreeMap), UnitStructNewType(UnitStruct), StructNewType(Struct), Struct { foo: i32, bar: bool, }, Tuple(i32, bool), UnitTwo, #[serde(with = "unit_variant_as_u64")] #[schemars(with = "u64")] UnitAsInt, #[serde(with = "tuple_variant_as_str")] #[schemars(schema_with = "tuple_variant_as_str::json_schema")] TupleAsStr(i32, bool), } impl Untagged { fn values() -> impl IntoIterator { [ Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { foo: 123, bar: true, }, Self::Tuple(456, false), Self::UnitTwo, Self::UnitAsInt, Self::TupleAsStr(789, true), ] } } mod unit_variant_as_u64 { pub(super) fn serialize(ser: S) -> Result where S: serde::Serializer, { ser.serialize_u64(42) } pub(super) fn deserialize<'de, D>(deser: D) -> Result<(), D::Error> where D: serde::Deserializer<'de>, { use serde::de::Deserialize; u64::deserialize(deser).map(|_| ()) } } mod tuple_variant_as_str { pub(super) fn serialize(i: &i32, b: &bool, ser: S) -> Result where S: serde::Serializer, { ser.collect_str(&format_args!("{i} {b}")) } pub(super) fn deserialize<'de, D>(deser: D) -> Result<(i32, bool), D::Error> where D: serde::Deserializer<'de>, { use serde::de::{Deserialize, Error}; let error = || Error::custom("invalid string"); let (i, b) = <&str>::deserialize(deser)? .split_once(' ') .ok_or_else(error)?; Ok(( i.parse().map_err(|_| error())?, b.parse().map_err(|_| error())?, )) } pub(super) fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { schemars::json_schema!({ "type": "string", "pattern": r"^\d+ (true|false)$" }) } } #[test] fn externally_tagged_enum() { test!(External) .assert_snapshot() .assert_allows_ser_roundtrip(External::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn internally_tagged_enum() { test!(Internal) .assert_snapshot() .assert_allows_ser_roundtrip(Internal::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn adjacently_tagged_enum() { test!(Adjacent) .assert_snapshot() .assert_allows_ser_roundtrip(Adjacent::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn untagged_enum() { test!(Untagged) .assert_snapshot() .assert_allows_ser_roundtrip(Untagged::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Serialize, Deserialize)] #[schemars(_unstable_ref_variants)] enum NoVariants {} #[test] fn no_variants() { test!(NoVariants) .assert_snapshot() .assert_rejects_de(arbitrary_values()); } #[derive(JsonSchema, Serialize, Deserialize)] #[serde(rename_all_fields = "UPPERCASE", rename_all = "snake_case")] #[schemars(_unstable_ref_variants)] enum Renamed { StructVariant { field: String, }, #[serde(rename = "custom name variant")] RenamedStructVariant { #[serde(rename = "custom name field")] field: String, }, } #[test] fn renamed() { test!(Renamed) .assert_snapshot() .assert_allows_ser_roundtrip([ Renamed::StructVariant { field: "foo".to_owned(), }, Renamed::RenamedStructVariant { field: "bar".to_owned(), }, ]) .assert_rejects_de(arbitrary_values()); } schemars-1.2.1/tests/integration/enums_untagged_variant.rs000064400000000000000000000113351046102023000222210ustar 00000000000000use crate::prelude::*; use std::collections::BTreeMap; #[derive(JsonSchema, Deserialize, Serialize)] struct UnitStruct; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { foo: i32, bar: bool, } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] enum External { TaggedUnitOne, TaggedStruct { baz: i32, foobar: bool, }, #[serde(untagged)] UnitOne, #[serde(untagged)] UnitStructNewType(UnitStruct), #[serde(untagged)] StructNewType(Struct), #[serde(untagged)] Struct { baz: i32, foobar: bool, }, #[serde(untagged)] Tuple(i32, bool), #[serde(untagged)] StringMap(BTreeMap), } impl External { fn values() -> impl IntoIterator { [ Self::TaggedUnitOne, Self::TaggedStruct { baz: 123, foobar: true, }, Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { baz: 123, foobar: true, }, Self::Tuple(456, false), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag")] enum Internal { TaggedUnitOne, TaggedStruct { baz: i32, foobar: bool, }, #[serde(untagged)] UnitOne, #[serde(untagged)] UnitStructNewType(UnitStruct), #[serde(untagged)] StructNewType(Struct), #[serde(untagged)] Struct { baz: i32, foobar: bool, }, // Internally-tagged enums don't support tuple variants // #[serde(untagged)] // Tuple(i32, bool), #[serde(untagged)] StringMap(BTreeMap), } impl Internal { fn values() -> impl IntoIterator { [ Self::TaggedUnitOne, Self::TaggedStruct { baz: 123, foobar: true, }, Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { baz: 123, foobar: true, }, // Self::Tuple(456, false), ] } } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(tag = "tag", content = "content")] enum Adjacent { TaggedUnitOne, TaggedStruct { baz: i32, foobar: bool, }, #[serde(untagged)] UnitOne, #[serde(untagged)] UnitStructNewType(UnitStruct), #[serde(untagged)] StructNewType(Struct), #[serde(untagged)] Struct { baz: i32, foobar: bool, }, #[serde(untagged)] Tuple(i32, bool), #[serde(untagged)] StringMap(BTreeMap), } impl Adjacent { fn values() -> impl IntoIterator { [ Self::TaggedUnitOne, Self::TaggedStruct { baz: 123, foobar: true, }, Self::UnitOne, Self::StringMap( [("hello".to_owned(), "world".to_owned())] .into_iter() .collect(), ), Self::UnitStructNewType(UnitStruct), Self::StructNewType(Struct { foo: 123, bar: true, }), Self::Struct { baz: 123, foobar: true, }, Self::Tuple(456, false), ] } } #[test] fn externally_tagged_enum() { test!(External) .assert_snapshot() .assert_allows_ser_roundtrip(External::values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn internally_tagged_enum() { test!(Internal) .assert_snapshot() .assert_allows_ser_roundtrip(Internal::values()) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "internally tagged enums can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); } #[test] fn adjacently_tagged_enum() { test!(Adjacent) .assert_snapshot() .assert_allows_ser_roundtrip(Adjacent::values()) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/examples.rs000064400000000000000000000005461046102023000173100ustar 00000000000000use crate::prelude::*; #[derive(Default, JsonSchema, Serialize)] #[schemars(example = Struct::default(), example = ())] struct Struct { #[schemars(example = 4 + 4, example = ())] foo: i32, bar: bool, #[schemars(example = (), example = &"foo")] baz: Option<&'static str>, } #[test] fn examples() { test!(Struct).assert_snapshot(); } schemars-1.2.1/tests/integration/extend.rs000064400000000000000000000110161046102023000167530ustar 00000000000000#![allow(clippy::approx_constant)] use crate::prelude::*; use pretty_assertions::assert_eq; static THREE: f64 = 3.0; #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(extend("obj" = {"array": [null, ()]}))] #[schemars(extend("3" = THREE), extend("pi" = THREE + 0.14))] struct Struct { #[schemars(extend("foo" = "bar"))] value: Value, #[schemars(extend("type" = ["number", "string"]))] int: i32, } #[test] fn extend_struct() { test!(Struct).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("obj"), Some(&json!({ "array": [null, null] }))); assert_eq!(schema.get("3"), Some(&json!(3.0))); assert_eq!(schema.get("pi"), Some(&json!(3.14))); assert_eq!( schema.as_value().pointer("/properties/value"), Some(&json!({ "foo": "bar" })) ); assert_eq!( schema.as_value().pointer("/properties/int/type"), Some(&json!(["number", "string"])) ); }); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(extend("obj" = {"array": [null, ()]}))] #[schemars(extend("3" = THREE), extend("pi" = THREE + 0.14))] struct TupleStruct( #[schemars(extend("foo" = "bar"))] Value, #[schemars(extend("type" = ["number", "string"]))] usize, ); #[test] fn extend_tuple_struct() { test!(TupleStruct).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("obj"), Some(&json!({ "array": [null, null] }))); assert_eq!(schema.get("3"), Some(&json!(3.0))); assert_eq!(schema.get("pi"), Some(&json!(3.14))); assert_eq!( schema.as_value().pointer("/prefixItems/0"), Some(&json!({ "foo": "bar" })) ); assert_eq!( schema.as_value().pointer("/prefixItems/1/type"), Some(&json!(["number", "string"])) ); }); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(extend("foo" = "bar"))] enum ExternalEnum { #[schemars(extend("foo" = "bar"))] Unit, #[schemars(extend("foo" = "bar"))] NewType(Value), #[schemars(extend("foo" = "bar"))] Tuple(i32, bool), #[schemars(extend("foo" = "bar"))] Struct { i: i32, b: bool }, } #[test] fn extend_externally_tagged_enum() { test!(ExternalEnum).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("foo"), Some(&json!("bar"))); for i in 0..4 { assert_eq!( schema.as_value().pointer(&format!("/oneOf/{i}/foo")), Some(&json!("bar")) ); } }); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(tag = "t", extend("foo" = "bar"))] enum InternalEnum { #[schemars(extend("foo" = "bar"))] Unit, #[schemars(extend("foo" = "bar"))] NewType(Value), #[schemars(extend("foo" = "bar"))] Struct { i: i32, b: bool }, } #[test] fn extend_internally_tagged_enum() { test!(InternalEnum).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("foo"), Some(&json!("bar"))); for i in 0..3 { assert_eq!( schema.as_value().pointer(&format!("/oneOf/{i}/foo")), Some(&json!("bar")) ); } }); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(tag = "t", content = "c", extend("foo" = "bar"))] enum AdjacentEnum { #[schemars(extend("foo" = "bar"))] Unit, #[schemars(extend("foo" = "bar"))] NewType(Value), #[schemars(extend("foo" = "bar"))] Tuple(i32, bool), #[schemars(extend("foo" = "bar"))] Struct { i: i32, b: bool }, } #[test] fn extend_adjacently_tagged_enum() { test!(AdjacentEnum).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("foo"), Some(&json!("bar"))); for i in 0..4 { assert_eq!( schema.as_value().pointer(&format!("/oneOf/{i}/foo")), Some(&json!("bar")) ); } }); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(untagged, extend("foo" = "bar"))] enum UntaggedEnum { #[schemars(extend("foo" = "bar"))] Unit, #[schemars(extend("foo" = "bar"))] NewType(Value), #[schemars(extend("foo" = "bar"))] Tuple(i32, bool), #[schemars(extend("foo" = "bar"))] Struct { i: i32, b: bool }, } #[test] fn extend_untagged_enum() { test!(UntaggedEnum).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("foo"), Some(&json!("bar"))); for i in 0..4 { assert_eq!( schema.as_value().pointer(&format!("/anyOf/{i}/foo")), Some(&json!("bar")) ); } }); } schemars-1.2.1/tests/integration/flatten.rs000064400000000000000000000041551046102023000171270ustar 00000000000000use crate::prelude::*; use std::collections::BTreeMap; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Flat { f: f32, b: bool, #[serde(default, skip_serializing_if = "str::is_empty")] s: String, v: Vec, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "Flat")] struct Deep1 { f: f32, #[serde(flatten)] deep2: Deep2, v: Vec, } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Deep2 { b: bool, #[serde(flatten, skip_serializing_if = "Option::is_none")] deep3: Option, } #[derive(JsonSchema, Deserialize, Serialize)] struct Deep3 { s: String, } #[test] fn flattened_struct() { test!(Deep1) .assert_snapshot() .assert_identical::() .assert_allows_ser_roundtrip([ Deep1::default(), Deep1 { f: 1.0, deep2: Deep2 { b: true, deep3: Some(Deep3 { s: "test".to_owned(), }), }, v: vec![123], }, ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct FlattenValue { flag: bool, #[serde(flatten)] value: Value, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "FlattenValue")] struct FlattenMap { flag: bool, #[serde(flatten)] value: BTreeMap, } #[test] fn flattened_value() { test!(FlattenValue) .assert_snapshot() .assert_allows_ser_roundtrip([ FlattenValue { flag: false, value: Value::Null, }, FlattenValue { flag: true, value: Value::Object(Default::default()), }, ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn flattened_map() { test!(FlattenMap) .assert_identical::() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/from_into.rs000064400000000000000000000033401046102023000174610ustar 00000000000000use std::num::ParseIntError; use crate::prelude::*; #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)] #[serde(into = "String", try_from = "String")] #[schemars(extend("pattern" = r"^[0-9a-f]{16}:[0-9a-f]{16}:[0-9a-f]{4}$"))] pub struct EventSequenceNumber { transaction_id: u64, statement_id: u64, write_id: u16, } impl From for String { fn from(value: EventSequenceNumber) -> Self { format!( "{:016x}:{:016x}:{:04x}", value.transaction_id, value.statement_id, value.write_id ) } } impl TryFrom for EventSequenceNumber { type Error = ParseIntError; fn try_from(value: String) -> Result { let mut parts = value.split(':'); Ok(Self { transaction_id: parts.next().unwrap_or_default().parse()?, statement_id: parts.next().unwrap_or_default().parse()?, write_id: parts.next().unwrap_or_default().parse()?, }) } } #[test] fn into_and_try_from() { test!(EventSequenceNumber) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)] #[serde(from = "i128")] struct ClampingI8(i8); impl From for ClampingI8 { fn from(value: i128) -> Self { Self(if value > i8::MAX as i128 { i8::MAX } else if value < i8::MIN as i128 { i8::MIN } else { value as i8 }) } } #[test] fn from() { test!(ClampingI8) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/from_value.rs000064400000000000000000000045551046102023000176350ustar 00000000000000use crate::prelude::*; use schemars::generate::SchemaSettings; use std::collections::BTreeMap; #[derive(Deserialize, Serialize, Default, Clone)] #[serde(rename_all = "camelCase")] pub struct MyStruct { pub my_int: i32, pub my_bool: bool, pub my_nullable_enum: Option, pub my_inner_struct: MyInnerStruct, #[serde(skip)] pub _skip: i32, #[serde(skip_serializing_if = "Option::is_none")] pub skip_if_none: Option, } #[derive(Deserialize, Serialize, Default, Clone)] pub struct MyInnerStruct { pub my_map: BTreeMap, pub my_vec: Vec, pub my_empty_map: BTreeMap, pub my_empty_vec: Vec, pub my_tuple: (char, u8), } #[derive(JsonSchema, Deserialize, Serialize, Clone)] pub enum MyEnum { NewType(String), Struct { floats: Vec }, } fn struct_value() -> MyStruct { MyStruct { my_int: 123, my_bool: true, my_nullable_enum: None, my_inner_struct: MyInnerStruct { my_map: [("k".to_owned(), 1.23)].into_iter().collect(), my_vec: vec![1.0, 2.0, 3.0], my_empty_map: BTreeMap::new(), my_empty_vec: Vec::new(), my_tuple: ('💩', 42), }, _skip: 123, skip_if_none: None, } } #[test] fn custom_struct() { let value = struct_value(); test!(value: value.clone()) .assert_snapshot() .assert_allows_ser_roundtrip([value, MyStruct::default()]); } #[test] fn custom_struct_openapi3() { let value = struct_value(); test!(value: value.clone(), SchemaSettings::openapi3()).assert_snapshot(); // schemars uses a nonstandard meta-schema for openapi 3.0 which the jsonschema crate doesn't // accept, so we swap it out for the standard draft-04 meta-schema. let draft04 = "http://json-schema.org/draft-04/schema"; test!(value: value.clone(), SchemaSettings::openapi3().with(|o| o.meta_schema = Some(draft04.into()))) .assert_allows_ser_roundtrip([value, MyStruct::default()]); } #[test] fn json_value() { let value = json!({ "zero": 0, "zeroPointZero": 0.0, "bool": true, "null": null, "object": { "strings": ["foo", "bar"], "mixed": [1, true] }, }); test!(value: value.clone()) .assert_snapshot() .assert_allows_ser_roundtrip([value]); } schemars-1.2.1/tests/integration/garde.rs000064400000000000000000000116551046102023000165570ustar 00000000000000#![allow(clippy::incompatible_msrv)] use crate::prelude::*; use garde::Validate; const ONE: usize = 1; const HUNDRED: usize = 10; #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct GardeAttrStruct { #[garde(range(min = 1.0, max = 100.0))] min_max: f32, #[garde(range(min = ONE as f32, max = HUNDRED as f32))] min_max2: f32, #[garde(pattern(r"^[Hh]ello"))] regex_str: String, #[garde(contains(concat!("sub","string...")))] contains_str: String, #[garde(email)] email_address: String, #[garde(url)] homepage: String, #[garde(length(min = ONE, max = HUNDRED))] non_empty_str: String, #[garde(length(equal = 2), inner(length(min = 1)))] pair: Vec, #[garde(required)] required_option: Option, #[garde(required, dive)] #[serde(flatten)] required_flattened: Option, } #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct GardeAttrInner { #[garde(range(min = -100, max = 100))] x: i32, } impl Default for GardeAttrStruct { fn default() -> Self { Self { min_max: 1.0, min_max2: 1.0, regex_str: "Hello world".to_owned(), contains_str: "Contains substring...".to_owned(), email_address: "test@test.test".to_owned(), homepage: "http://test.test".to_owned(), non_empty_str: "test".to_owned(), pair: vec!["a".to_owned(), "b".to_owned()], required_option: Some(true), required_flattened: Some(GardeAttrInner { x: 0 }), } } } impl GardeAttrStruct { pub fn invalid_values() -> impl IntoIterator { static MUTATORS: &[fn(&mut GardeAttrStruct)] = &[ |v| v.min_max = 0.9, |v| v.min_max = 100.1, |v| v.min_max2 = 0.9, |v| v.min_max2 = 100.1, |v| v.regex_str = "fail".to_owned(), |v| v.contains_str = "fail".to_owned(), |v| v.email_address = "fail".to_owned(), |v| v.homepage = "fail".to_owned(), |v| v.non_empty_str = String::new(), |v| v.pair = Vec::new(), |v| v.pair = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()], |v| v.pair = vec!["".to_owned(), "b".to_owned()], |v| v.required_option = None, |v| v.required_flattened = None, |v| v.required_flattened = Some(GardeAttrInner { x: -101 }), |v| v.required_flattened = Some(GardeAttrInner { x: 101 }), ]; MUTATORS.iter().map(|f| { let mut result = GardeAttrStruct::default(); f(&mut result); result }) } } #[test] fn garde_attrs() { test!(GardeAttrStruct) .with_validator(|v| v.validate().is_ok()) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_rejects_invalid(GardeAttrStruct::invalid_values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(rename = "GardeAttrStruct")] pub struct SchemarsAttrStruct { #[schemars(range(min = 1.0, max = 100.0))] min_max: f32, #[schemars(range(min = ONE as f32, max = HUNDRED as f32))] min_max2: f32, #[schemars(pattern(r"^[Hh]ello"))] regex_str: String, #[schemars(contains(concat!("sub","string...")))] contains_str: String, #[schemars(email)] email_address: String, #[schemars(url)] homepage: String, #[schemars(length(min = ONE, max = HUNDRED))] non_empty_str: String, #[schemars(length(equal = 2), inner(length(min = 1)))] pair: Vec, #[schemars(required)] required_option: Option, #[schemars(required)] #[serde(flatten)] required_flattened: Option, } #[allow(dead_code)] #[derive(JsonSchema)] pub struct SchemarsAttrInner { #[schemars(range(min = -100, max = 100))] x: i32, } #[test] fn schemars_attrs() { test!(SchemarsAttrStruct).assert_identical::(); } #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct GardeAttrTuple( #[garde(range(max = 10))] u8, #[garde(required)] Option, ); #[test] fn garde_attrs_tuple() { test!(GardeAttrTuple) .with_validator(|v| v.validate().is_ok()) .assert_snapshot() .assert_allows_ser_roundtrip([GardeAttrTuple(10, Some(false))]) .assert_rejects_invalid([GardeAttrTuple(11, Some(false)), GardeAttrTuple(10, None)]) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct GardeAttrNewType(#[garde(range(max = 10))] u8); #[test] fn garde_attrs_newtype() { test!(GardeAttrNewType) .with_validator(|v| v.validate().is_ok()) .assert_snapshot() .assert_allows_ser_roundtrip([GardeAttrNewType(10)]) .assert_rejects_invalid([GardeAttrNewType(11)]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/indexmap.rs000064400000000000000000000011651046102023000172750ustar 00000000000000use crate::prelude::*; use indexmap2::{indexmap, indexset, IndexMap, IndexSet}; use std::collections::{BTreeMap, BTreeSet}; #[test] fn indexmap() { test!(IndexMap) .assert_identical::>() .assert_allows_ser_roundtrip([indexmap!(), indexmap!("key".to_owned() => true)]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn indexset() { test!(IndexSet) .assert_identical::>() .assert_allows_ser_roundtrip([indexset!(), indexset!("test".to_owned())]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/inline_subschemas.rs000064400000000000000000000033141046102023000211610ustar 00000000000000use crate::prelude::*; use schemars::generate::SchemaSettings; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct MyJob { spec: MyJobSpec, } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct MyJobSpec { replicas: u32, } #[test] fn struct_normal() { let settings = SchemaSettings::default().with(|s| s.inline_subschemas = true); test!(MyJob, settings) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] struct RecursiveOuter { direct: Option>, indirect: Option>, } #[derive(JsonSchema, Deserialize, Serialize)] struct RecursiveInner { recursive: RecursiveOuter, } #[test] fn struct_recursive() { let settings = SchemaSettings::default().with(|s| s.inline_subschemas = true); test!(RecursiveOuter, settings) .assert_snapshot() .assert_allows_ser_roundtrip([ RecursiveOuter { direct: None, indirect: None, }, RecursiveOuter { direct: Some(Box::new(RecursiveOuter { direct: None, indirect: None, })), indirect: Some(Box::new(RecursiveInner { recursive: RecursiveOuter { direct: Some(Box::new(RecursiveOuter { direct: None, indirect: None, })), indirect: None, }, })), }, ]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/jiff.rs000064400000000000000000000033061046102023000164050ustar 00000000000000use crate::prelude::*; use jiff02::civil::{Date, DateTime, Time}; use jiff02::{SignedDuration, Span, Timestamp, Zoned}; #[derive(JsonSchema, Serialize, Deserialize)] struct JiffTypes { date_time_ts: Timestamp, date_time_zoned: Zoned, naive_date: Date, naive_date_time: DateTime, naive_time: Time, duration: SignedDuration, span: Span, } #[test] fn jiff() { test!(JiffTypes).assert_snapshot(); test!(Timestamp) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); test!(Zoned) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'zoned-date-time', so arbitrary strings technically allowed by schema", )); test!(Date) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); test!(DateTime) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'partial-date-time', so arbitrary strings technically allowed by schema", )); test!(Time) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'date-time', so arbitrary strings technically allowed by schema", )); test!(SignedDuration) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); test!(Span) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/macros.rs000064400000000000000000000025031046102023000167510ustar 00000000000000use crate::prelude::*; macro_rules! build_struct { ( $id:ident { $($t:tt)* } ) => { #[derive(JsonSchema, Deserialize, Serialize, Default)] pub struct $id { x: u8, $($t)* } }; } build_struct!(A { v: i32 }); #[test] fn macro_built_struct() { test!(A).assert_allows_ser_roundtrip_default(); } macro_rules! build_enum { ( $(#[$outer_derive:meta])* $outer:ident { $($(#[$inner_derive:meta])* $inner:ident { $( $(#[$field_attribute:meta])* $field:ident : $ty:ty),* })* } ) => { $( $(#[$inner_derive])* pub struct $inner { $( $(#[$field_attribute])* pub $field: $ty ),* } )* $(#[$outer_derive])* pub enum $outer { $( $inner($inner) ),* } } } build_enum!( #[derive(JsonSchema, Deserialize, Serialize)] OuterEnum { #[derive(JsonSchema, Deserialize, Serialize, Default)] InnerStruct { x: i32 } } ); #[test] fn macro_built_enum() { test!(OuterEnum).assert_allows_ser_roundtrip([OuterEnum::InnerStruct(InnerStruct::default())]); } schemars-1.2.1/tests/integration/main.rs000064400000000000000000000044641046102023000164210ustar 00000000000000#![allow(clippy::disallowed_names)] #[cfg(feature = "arrayvec07")] mod arrayvec; mod attr_order; mod bound; #[cfg(feature = "bytes1")] mod bytes; #[cfg(feature = "chrono04")] mod chrono; mod contract; mod crate_alias; #[cfg(any(feature = "rust_decimal1", feature = "bigdecimal04"))] mod decimal; mod default; mod deprecated; mod docs; #[cfg(feature = "either1")] mod either; mod enum_repr; mod enums; mod enums_deny_unknown_fields; mod enums_flattened; mod enums_option_flattened; mod enums_ref_variants; mod enums_untagged_variant; mod examples; mod extend; mod flatten; mod from_into; mod from_value; mod garde; #[cfg(feature = "indexmap2")] mod indexmap; mod inline_subschemas; #[cfg(feature = "jiff02")] mod jiff; mod macros; mod map; mod remote_derive; mod same_name; mod schema_name; mod schema_with; #[cfg(feature = "semver1")] mod semver; mod settings; mod skip; #[cfg(feature = "smallvec1")] mod smallvec; #[cfg(any(feature = "smol_str02", feature = "smol_str03"))] mod smol_str; mod std_types; mod structs; mod transform; mod transparent; mod unset; #[cfg(feature = "url2")] mod url; #[cfg(feature = "uuid1")] mod uuid; mod validator; mod prelude { pub(crate) use crate::test; pub(crate) use crate::test_helper::{arbitrary_values, arbitrary_values_except}; pub(crate) use schemars::JsonSchema; pub(crate) use serde::{Deserialize, Serialize}; pub(crate) use serde_json::{json, Value}; } mod test_helper; #[macro_export] macro_rules! test_name { () => {{ fn f() {} fn type_name_of_val(_: T) -> &'static str { core::any::type_name::() } let test_fn_name = type_name_of_val(f) .trim_end_matches("::f") .split("::") .last() .unwrap(); format!("{}~{}", core::file!(), test_fn_name) }}; } #[macro_export] macro_rules! test { ($type:ty, $settings:expr) => { $crate::test_helper::TestHelper::<$type>::new($crate::test_name!(), $settings) }; ($type:ty) => { test!($type, schemars::generate::SchemaSettings::default()) }; (value: $value:expr, $settings:expr) => { $crate::test_helper::TestHelper::new_for_value($crate::test_name!(), $settings, $value) }; (value: $value:expr) => { test!(value: $value, schemars::generate::SchemaSettings::default()) }; } schemars-1.2.1/tests/integration/map.rs000064400000000000000000000040741046102023000162470ustar 00000000000000use crate::prelude::*; use std::collections::{BTreeMap, HashMap}; #[derive(JsonSchema, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)] #[schemars(extend("pattern" = "^[0-9a-f]*$"))] struct HexNumber(String); #[derive(JsonSchema, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] struct IndirectU32(u32); #[derive(JsonSchema, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] enum Enum { Unit1, Unit2, #[serde(untagged)] UntaggedI8(i8), #[serde(untagged)] UntaggedIndirectU32(IndirectU32), } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Maps { s_map: HashMap, i_map: BTreeMap, u_map: HashMap, pattern_map: BTreeMap, enum_map: HashMap, } #[test] fn maps() { test!(Maps) .assert_snapshot() .assert_allows_ser_roundtrip([Maps { s_map: HashMap::from_iter([("test".to_owned(), true)]), i_map: BTreeMap::from_iter([(-123, true), (123, true)]), u_map: HashMap::from_iter([(123, true)]), pattern_map: BTreeMap::from_iter([(HexNumber("b4df00d".to_owned()), true)]), enum_map: HashMap::from_iter([(Enum::Unit1, true)]), }]) .assert_allows_ser_only( // serde allow serializing untagged non-string newtype variants, but not deserializing them. [ Maps { enum_map: HashMap::from_iter([(Enum::UntaggedI8(-100), true)]), ..Default::default() }, Maps { // It's unfortunate that this adds an unused `IndirectU32` to the schema's `$defs`, // but it's ultimately harmless. enum_map: HashMap::from_iter([( Enum::UntaggedIndirectU32(IndirectU32(1000000)), true, )]), ..Default::default() }, ], ) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/remote_derive.rs000064400000000000000000000041061046102023000203170ustar 00000000000000use crate::prelude::*; mod external { #[derive(Default)] pub struct Duration { pub secs: i64, pub nanos: i32, } #[allow(dead_code)] pub enum Or { A(A), B(B), } pub struct Str<'a>(pub &'a str); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(remote = "external::Duration")] struct DurationDef { secs: i64, nanos: i32, } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Process { #[serde(with = "DurationDef")] wall_time: external::Duration, } #[test] fn simple() { test!(Process) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(untagged, remote = "external::Or")] #[schemars(rename = "{A}_or_{B}")] enum OrDef { A(A), B(B), } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(bound = "T: serde::de::DeserializeOwned + Serialize")] struct TypeParam { #[serde(with = "OrDef::")] byte_or_bool: external::Or, #[serde(with = "OrDef::<(), T>")] unit_or_t: external::Or<(), T>, } #[test] fn type_param() { test!(TypeParam) .assert_snapshot() .assert_allows_ser_roundtrip([ TypeParam { byte_or_bool: external::Or::A(123), unit_or_t: external::Or::A(()), }, TypeParam { byte_or_bool: external::Or::B(true), unit_or_t: external::Or::B("test".to_owned()), }, ]) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Serialize)] #[serde(remote = "external::Str")] struct StrDef<'a>(&'a str); #[derive(JsonSchema, Deserialize, Serialize)] struct LifetimeParam<'a> { #[serde(borrow, with = "StrDef")] s: external::Str<'a>, } #[test] fn lifetime_param() { let s = external::Str("test"); test!(LifetimeParam) .assert_snapshot() .assert_allows_ser_only([LifetimeParam { s }]); } schemars-1.2.1/tests/integration/same_name.rs000064400000000000000000000014651046102023000174200ustar 00000000000000use crate::prelude::*; mod a { use super::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] pub struct Config { test: String, } } mod b { use super::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] pub struct Config { test2: String, } } mod c { use super::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "Config")] pub struct Configuration { test3: String, } } #[derive(JsonSchema, Deserialize, Serialize, Default)] pub struct Config2 { a_cfg: a::Config, b_cfg: b::Config, c_cfg: c::Configuration, } #[test] fn same_name() { test!(Config2) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/schema_name.rs000064400000000000000000000056671046102023000177430ustar 00000000000000use crate::prelude::*; use pretty_assertions::assert_eq; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct SimpleStruct { foo: i32, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "new-name")] struct RenamedSimpleStruct { foo: i32, } #[test] fn simple() { test!(SimpleStruct) .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"SimpleStruct".into()))); test!(RenamedSimpleStruct) .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"new-name".into()))); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct TypeParams { t: T, u: U, v: V, w: W, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "new name~{W}/{T}/{T}!")] struct RenamedTypeParams { t: T, u: U, v: V, w: W, } #[test] fn type_params() { test!(TypeParams) .assert_allows_ser_roundtrip_default() .assert_identical::, bool, ()>>(); assert_ne!( >::schema_id(), >::schema_id() ); test!(RenamedTypeParams) .assert_allows_ser_roundtrip_default() .assert_identical::, bool, ()>>() .custom(|schema, _| { assert_eq!( schema.get("title"), Some(&"new name~null/uint8/uint8!".into()) ) }); assert_ne!( >::schema_id(), >::schema_id() ); test!(( TypeParams, RenamedTypeParams )) .assert_allows_ser_roundtrip_default() .custom(|schema, _| { assert_eq!( schema.pointer("/prefixItems/1/$ref"), Some(&("#/$defs/new%20name~0null~1uint8~1uint8!".into())), "name should be correctly encoded for $ref value" ) }); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct ConstGeneric { #[schemars(range(max = INT))] foo: i32, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(rename = "{{new-name-{INT}}}")] struct RenamedConstGeneric { #[schemars(range(max = INT))] foo: i32, } #[test] fn const_generics() { test!(ConstGeneric<123, 'X'>).assert_allows_ser_roundtrip_default(); assert_ne!( >::schema_id(), >::schema_id() ); test!(RenamedConstGeneric<123, 'X'>) .assert_allows_ser_roundtrip_default() .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"{new-name-123}".into()))); assert_ne!( >::schema_id(), >::schema_id() ); } schemars-1.2.1/tests/integration/schema_with.rs000064400000000000000000000060001046102023000177540ustar 00000000000000use crate::prelude::*; use schemars::generate::SchemaSettings; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { #[serde(with = "int_as_str")] #[schemars(schema_with = "int_as_str::json_schema")] x: i64, #[schemars(schema_with = "from_serialize_default::")] t: T, } mod int_as_str { pub(super) fn serialize(value: &T, ser: S) -> Result where S: serde::Serializer, T: std::fmt::Display, { ser.collect_str(value) } pub(super) fn deserialize<'de, D, T>(deser: D) -> Result where D: serde::Deserializer<'de>, T: std::str::FromStr, { <&str as serde::Deserialize>::deserialize(deser)? .parse() .map_err(serde::de::Error::custom) } pub(super) fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { schemars::json_schema!({ "type": "string", "pattern": r"^-?\d+$" }) } } fn from_serialize_default( generator: &mut schemars::SchemaGenerator, ) -> schemars::Schema { generator .settings() .clone() .into_generator() .into_root_schema_for_value(&T::default()) .unwrap() } #[test] fn field_schema_with() { test!(Struct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); } struct NotJsonSchema; #[derive(JsonSchema)] #[schemars(with = "Struct")] struct Struct2 { _x: NotJsonSchema, } #[test] fn container_with() { test!(Struct2).assert_identical::>(); } #[derive(JsonSchema)] #[schemars(with = "Struct", description = "Testing...")] struct Struct3 { _x: NotJsonSchema, } #[test] fn container_with_metadata() { test!(Struct3).assert_snapshot().custom(|schema, _| { assert_eq!(schema.get("description"), Some(&"Testing...".into())); }); assert_ne!(::schema_id(), ::schema_id()); } #[derive(JsonSchema)] #[schemars(schema_with = "int_as_str::json_schema")] struct IntAsString { _x: NotJsonSchema, } #[test] fn container_schema_with() { test!(IntAsString) .assert_snapshot() .custom(|schema, contract| { let mut generator = SchemaSettings::default() .with(|s| s.contract = contract) .into_generator(); let expected = int_as_str::json_schema(&mut generator); // `title` and `$schema` are added for root schemas - ignore for comparison purposes let mut schema = schema.clone(); schema.remove("title"); schema.remove("$schema"); assert_eq!(schema, expected); }); } schemars-1.2.1/tests/integration/semver.rs000064400000000000000000000013741046102023000167730ustar 00000000000000use crate::prelude::*; use semver1::Version; #[test] fn semver() { test!(Version) .assert_snapshot() .assert_allows_de_roundtrip( [ "1.2.3", "1.2.3-alpha4", "1.2.3+build4", "1.2.3+04", "1.2.3-1.alpha.2+5.build.4.3-21", ] .into_iter() .map(Value::from), ) .assert_rejects_de( [ "1.2", "1.2.3.4", "1.2.03", "1.2.3-alpha..", "1.2.3-alpha.04", "1.2.3++", ] .into_iter() .map(Value::from), ) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/settings.rs000064400000000000000000000045721046102023000173350ustar 00000000000000use crate::prelude::*; use pretty_assertions::assert_eq; use schemars::{generate::SchemaSettings, Schema}; #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(inline)] pub struct OuterStruct { #[schemars(extend("examples" = [8, null]))] maybe_int: Option, values: serde_json::Map, value: Value, inner: InnerEnum, maybe_inner: Option, tuples: Vec<(u8, i64)>, } #[derive(JsonSchema, Deserialize, Serialize, Default)] pub enum InnerEnum { #[default] UndocumentedUnit1, UndocumentedUnit2, /// This is a documented unit variant DocumentedUnit, ValueNewType(Value), } #[test] fn draft07() { test!(OuterStruct, SchemaSettings::draft07()) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn draft2019_09() { test!(OuterStruct, SchemaSettings::draft2019_09()) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn draft2020_12() { test!(OuterStruct, SchemaSettings::draft2020_12()) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn openapi3() { let mut settings = SchemaSettings::openapi3(); // Hack to apply recursive transforms to schemas at components.schemas: // First, move them to $defs, then run the transforms, then move them back again. settings.transforms.insert( 0, Box::new(|s: &mut Schema| { let defs = s.pointer_mut("/components/schemas").unwrap().take(); s.insert("$defs".to_owned(), defs); }), ); settings.transforms.push(Box::new(|s: &mut Schema| { *s.pointer_mut("/components/schemas").unwrap() = s.remove("$defs").unwrap(); })); test!(OuterStruct, settings.clone()).assert_snapshot(); // Ensure that `take_definitions()` applies transforms correctly let gen1 = settings.into_generator(); let definitions1 = &Value::from(gen1.into_root_schema_for::())["components"]["schemas"]; let mut gen2 = SchemaSettings::openapi3().into_generator(); gen2.subschema_for::(); let definitions2 = Value::Object(gen2.take_definitions(true)); assert_eq!(definitions1, &definitions2); } schemars-1.2.1/tests/integration/skip.rs000064400000000000000000000021071046102023000164330ustar 00000000000000use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct Struct { #[serde(skip)] _skipped: bool, included: bool, } #[test] fn skip_struct_field() { test!(Struct) .assert_snapshot() .assert_allows_de_roundtrip([json!({ "included": true })]) .assert_rejects_de([json!({ "_skipped": true, "included": true })]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); } #[derive(JsonSchema, Deserialize, Serialize)] pub enum Enum { Included1, #[serde(skip)] _Skipped, Included2, } #[test] fn skip_enum_variants() { test!(Enum) .assert_snapshot() .assert_allows_de_roundtrip([json!("Included1"), json!("Included2")]) .assert_rejects_de([json!("_Skipped")]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/smallvec.rs000064400000000000000000000004511046102023000172730ustar 00000000000000use crate::prelude::*; use smallvec1::{smallvec, SmallVec}; #[test] fn smallvec() { test!(SmallVec<[usize; 2]>) .assert_identical::>() .assert_allows_ser_roundtrip([smallvec![], smallvec![1, 2, 3, 4, 5]]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/smol_str.rs000064400000000000000000000010171046102023000173260ustar 00000000000000use crate::prelude::*; #[cfg(feature = "smol_str02")] #[test] fn smol_str02() { test!(smol_str02::SmolStr) .assert_identical::() .assert_allows_ser_roundtrip(["".into(), "test".into()]) .assert_matches_de_roundtrip(arbitrary_values()); } #[cfg(feature = "smol_str03")] #[test] fn smol_str03() { test!(smol_str03::SmolStr) .assert_identical::() .assert_allows_ser_roundtrip(["".into(), "test".into()]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json000064400000000000000000000003141046102023000316650ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Array_up_to_size_8_of_int32", "type": "array", "items": { "type": "integer", "format": "int32" }, "maxItems": 8 }././@LongLink00006440000000000000000000000170000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/attr_order.rs~attributes_applied_in_order.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/attr_order.rs~attributes_appli000064400000000000000000000005651046102023000326460ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "description": "The enum...", "anyOf": [ { "description": "The variant?", "type": "object", "properties": { "i": { "description": "The field! (At least 1)", "type": "integer", "format": "int32" } } } ] }././@LongLink00006440000000000000000000000171000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/attr_order.rs~attributes_applied_in_order.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/attr_order.rs~attributes_appli000064400000000000000000000006361046102023000326450ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "description": "The enum...", "anyOf": [ { "description": "The variant?", "type": "object", "properties": { "i": { "description": "The field! (At least 1)", "type": "integer", "format": "int32" } }, "required": [ "i" ] } ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/bound.rs~auto_bound.de.json000064400000000000000000000004371046102023000317310ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyContainer2", "type": "object", "properties": { "u": { "type": [ "string", "null" ] }, "phantom": { "type": "null" } }, "required": [ "phantom" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/bound.rs~auto_bound.ser.json000064400000000000000000000004501046102023000321250ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyContainer2", "type": "object", "properties": { "u": { "type": [ "string", "null" ] }, "phantom": { "type": "null" } }, "required": [ "u", "phantom" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/bound.rs~manual_bound_set.json000064400000000000000000000005351046102023000325210ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyContainer", "type": "object", "properties": { "associated": { "type": "string" }, "associated2": { "type": "string" }, "phantom": { "type": "null" } }, "required": [ "associated", "associated2", "phantom" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.de.json000064400000000000000000000003431046102023000307330ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Bytes", "type": [ "array", "string" ], "items": { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json000064400000000000000000000003131046102023000311310ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Bytes", "type": "array", "items": { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json000064400000000000000000000020651046102023000306530ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ChronoTypes", "type": "object", "properties": { "weekday": { "type": "string", "enum": [ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" ] }, "date_time": { "type": "string", "format": "date-time" }, "naive_date": { "type": "string", "format": "date" }, "naive_date_time": { "type": "string", "format": "partial-date-time" }, "naive_time": { "type": "string", "format": "partial-time" }, "time_delta": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int64" }, { "type": "integer", "minimum": 0, "exclusiveMaximum": 1000000000 } ], "minItems": 2, "maxItems": 2 } }, "required": [ "weekday", "date_time", "naive_date", "naive_date_time", "naive_time", "time_delta" ] }././@LongLink00006440000000000000000000000161000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_000064400000000000000000000026101046102023000325240ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AdjacentEnum", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "WriteOnlyUnit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "WriteOnlyStruct" }, "content": { "type": "object", "properties": { "i": { "type": "integer", "format": "int" } }, "required": [ "i" ] } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "de_renamed_unit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "de_renamed_struct" }, "content": { "type": "object", "properties": { "b": { "type": "boolean" } }, "required": [ "b" ] } }, "required": [ "tag", "content" ] } ] }././@LongLink00006440000000000000000000000162000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_000064400000000000000000000025541046102023000325330ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AdjacentEnum", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "READ-ONLY-UNIT" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "READ-ONLY-STRUCT" }, "content": { "type": "object", "properties": { "S": { "type": "string" } }, "required": [ "S" ] } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "ser_renamed_unit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "ser_renamed_struct" }, "content": { "type": "object", "properties": { "B": { "type": "boolean" } }, "required": [ "B" ] } }, "required": [ "tag", "content" ] } ] }././@LongLink00006440000000000000000000000161000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_000064400000000000000000000017721046102023000326050ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalEnum", "oneOf": [ { "type": "string", "enum": [ "WriteOnlyUnit", "de_renamed_unit" ] }, { "type": "object", "properties": { "WriteOnlyStruct": { "type": "object", "properties": { "i": { "type": "integer", "format": "int" } }, "required": [ "i" ] } }, "required": [ "WriteOnlyStruct" ], "additionalProperties": false }, { "type": "object", "properties": { "de_renamed_struct": { "type": "object", "properties": { "b": { "type": "boolean" } }, "required": [ "b" ] } }, "required": [ "de_renamed_struct" ], "additionalProperties": false } ] }././@LongLink00006440000000000000000000000162000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_000064400000000000000000000017401046102023000326000ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalEnum", "oneOf": [ { "type": "string", "enum": [ "READ-ONLY-UNIT", "ser_renamed_unit" ] }, { "type": "object", "properties": { "READ-ONLY-STRUCT": { "type": "object", "properties": { "S": { "type": "string" } }, "required": [ "S" ] } }, "required": [ "READ-ONLY-STRUCT" ], "additionalProperties": false }, { "type": "object", "properties": { "ser_renamed_struct": { "type": "object", "properties": { "B": { "type": "boolean" } }, "required": [ "B" ] } }, "required": [ "ser_renamed_struct" ], "additionalProperties": false } ] }././@LongLink00006440000000000000000000000161000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_000064400000000000000000000020641046102023000325720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "InternalEnum", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "WriteOnlyUnit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "i": { "type": "integer", "format": "int" }, "tag": { "type": "string", "const": "WriteOnlyStruct" } }, "required": [ "tag", "i" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "de_renamed_unit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "b": { "type": "boolean" }, "tag": { "type": "string", "const": "de_renamed_struct" } }, "required": [ "tag", "b" ] } ] }././@LongLink00006440000000000000000000000162000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_000064400000000000000000000020341046102023000325670ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "InternalEnum", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "READ-ONLY-UNIT" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "S": { "type": "string" }, "tag": { "type": "string", "const": "READ-ONLY-STRUCT" } }, "required": [ "tag", "S" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "ser_renamed_unit" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "B": { "type": "boolean" }, "tag": { "type": "string", "const": "ser_renamed_struct" } }, "required": [ "tag", "B" ] } ] }././@LongLink00006440000000000000000000000166000000000000007776Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unkno000064400000000000000000000010671046102023000326750ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "StructAllowUnknownFields", "type": "object", "properties": { "write_only": { "type": "boolean", "writeOnly": true }, "default": { "type": "boolean", "default": false }, "skip_serializing_if": { "type": "boolean" }, "de_renamed": { "type": "boolean" }, "option": { "type": [ "boolean", "null" ] } }, "required": [ "write_only", "skip_serializing_if", "de_renamed" ] }././@LongLink00006440000000000000000000000167000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unkno000064400000000000000000000011201046102023000326630ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "StructAllowUnknownFields", "type": "object", "properties": { "READ-ONLY": { "type": "boolean", "readOnly": true, "default": false }, "DEFAULT": { "type": "boolean", "default": false }, "SKIP-SERIALIZING-IF": { "type": "boolean" }, "ser_renamed": { "type": "boolean" }, "OPTION": { "type": [ "boolean", "null" ] } }, "required": [ "READ-ONLY", "DEFAULT", "ser_renamed", "OPTION" ] }././@LongLink00006440000000000000000000000165000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknow000064400000000000000000000011271046102023000327020ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "StructDenyUnknownFields", "type": "object", "properties": { "write_only": { "type": "boolean", "writeOnly": true }, "default": { "type": "boolean", "default": false }, "skip_serializing_if": { "type": "boolean" }, "de_renamed": { "type": "boolean" }, "option": { "type": [ "boolean", "null" ] } }, "additionalProperties": false, "required": [ "write_only", "skip_serializing_if", "de_renamed" ] }././@LongLink00006440000000000000000000000166000000000000007776Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknow000064400000000000000000000011601046102023000326770ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "StructDenyUnknownFields", "type": "object", "properties": { "READ-ONLY": { "type": "boolean", "readOnly": true, "default": false }, "DEFAULT": { "type": "boolean", "default": false }, "SKIP-SERIALIZING-IF": { "type": "boolean" }, "ser_renamed": { "type": "boolean" }, "OPTION": { "type": [ "boolean", "null" ] } }, "additionalProperties": false, "required": [ "READ-ONLY", "DEFAULT", "ser_renamed", "OPTION" ] }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.js000064400000000000000000000005171046102023000324770ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TupleStruct", "type": "array", "prefixItems": [ { "type": "string" }, { "type": "boolean", "writeOnly": true }, { "type": "string" }, { "type": "string" } ], "minItems": 4, "maxItems": 4 }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.j000064400000000000000000000005161046102023000325140ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TupleStruct", "type": "array", "prefixItems": [ { "type": "string" }, { "type": "string" }, { "type": "boolean", "readOnly": true }, { "type": "string" } ], "minItems": 4, "maxItems": 4 }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.j000064400000000000000000000010141046102023000323720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UntaggedEnum", "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "i": { "type": "integer", "format": "int" } }, "required": [ "i" ] }, { "type": "null" }, { "type": "object", "properties": { "b": { "type": "boolean" } }, "required": [ "b" ] } ] }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.000064400000000000000000000007601046102023000324300ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UntaggedEnum", "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "S": { "type": "string" } }, "required": [ "S" ] }, { "type": "null" }, { "type": "object", "properties": { "B": { "type": "boolean" } }, "required": [ "B" ] } ] }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.js000064400000000000000000000002571046102023000323460ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Decimal", "type": [ "string", "number" ], "pattern": "^-?\\d+(\\.\\d+)?([eE]\\d+)?$" }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.j000064400000000000000000000002141046102023000323550ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Decimal", "type": "string", "pattern": "^-?\\d+(\\.\\d+)?$" }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.j000064400000000000000000000014731046102023000323420ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "integer": { "type": "integer", "format": "uint32", "minimum": 0, "default": 0 }, "boolean": { "type": "boolean", "default": false }, "option_string": { "type": [ "string", "null" ], "default": null }, "string_skip_empty": { "type": "string" }, "struct2": { "type": "string", "pattern": "^\\d+ (true|false)$", "default": "0 false" }, "not_serialize": { "$ref": "#/$defs/NotSerialize", "writeOnly": true } }, "$defs": { "NotSerialize": { "type": "integer", "format": "int8", "minimum": -128, "maximum": 127 } } }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.000064400000000000000000000012521046102023000323640ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "integer": { "type": "integer", "format": "uint32", "minimum": 0, "default": 0 }, "boolean": { "type": "boolean", "default": false }, "option_string": { "type": [ "string", "null" ], "default": null }, "string_skip_empty": { "type": "string" }, "struct2": { "type": "string", "pattern": "^\\d+ (true|false)$", "default": "0 false" } }, "required": [ "integer", "boolean", "option_string", "struct2" ] }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.000064400000000000000000000016251046102023000324260ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "DeprecatedEnum", "oneOf": [ { "type": "string", "enum": [ "Unit" ] }, { "type": "string", "const": "DeprecatedUnitVariant", "deprecated": true }, { "type": "object", "properties": { "DeprecatedStructVariant": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "deprecated_field": { "type": "boolean", "deprecated": true } }, "required": [ "foo", "deprecated_field" ] } }, "required": [ "DeprecatedStructVariant" ], "additionalProperties": false, "deprecated": true } ], "deprecated": true }././@LongLink00006440000000000000000000000153000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struc000064400000000000000000000005231046102023000325400ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "DeprecatedStruct", "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean", "deprecated": true } }, "required": [ "foo", "bar" ], "deprecated": true }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.j000064400000000000000000000020761046102023000323720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "This is the enum's title", "description": "This is \nthe enum's description.", "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit", "UndocumentedUnit2" ] }, { "description": "This comment is included in the generated schema :)", "type": "string", "const": "DocumentedUnit" }, { "title": "Complex variant", "description": "This is a struct-like variant.", "type": "object", "properties": { "Complex": { "type": "object", "properties": { "my_nullable_string": { "title": "A nullable string", "description": "This field is a nullable string.\n\nThis\nis\n the second\n line!\n\n\n\n\nAnd this is the third!", "type": [ "string", "null" ] } } } }, "required": [ "Complex" ], "additionalProperties": false } ] }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.000064400000000000000000000022041046102023000324120ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "This is the enum's title", "description": "This is \nthe enum's description.", "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit", "UndocumentedUnit2" ] }, { "description": "This comment is included in the generated schema :)", "type": "string", "const": "DocumentedUnit" }, { "title": "Complex variant", "description": "This is a struct-like variant.", "type": "object", "properties": { "Complex": { "type": "object", "properties": { "my_nullable_string": { "title": "A nullable string", "description": "This field is a nullable string.\n\nThis\nis\n the second\n line!\n\n\n\n\nAnd this is the third!", "type": [ "string", "null" ] } }, "required": [ "my_nullable_string" ] } }, "required": [ "Complex" ], "additionalProperties": false } ] }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.000064400000000000000000000011211046102023000324720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "OverrideDocs struct", "description": "New description", "type": "object", "properties": { "my_int": { "title": "My integer", "description": "This is an i32", "type": "integer", "format": "int32" }, "my_undocumented_bool": { "type": "boolean" }, "my_documented_bool": { "title": "Documented bool", "description": "CAPITALIZED", "type": "boolean" } }, "required": [ "my_int", "my_undocumented_bool", "my_documented_bool" ] }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.js000064400000000000000000000014461046102023000325460ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "This is the struct's title", "description": "This is the struct's description.", "type": "object", "properties": { "my_int": { "title": "An integer", "type": "integer", "format": "int32" }, "my_undocumented_bool": { "type": "boolean" }, "my_unit": { "description": "A unit struct instance", "$ref": "#/$defs/MyUnitStruct" }, "my_documented_bool": { "title": "Documented bool", "description": "This bool is documented", "type": "boolean" } }, "required": [ "my_int", "my_undocumented_bool", "my_unit", "my_documented_bool" ], "$defs": { "MyUnitStruct": { "title": "A Unit", "type": "null" } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/either.rs~either.json000064400000000000000000000022271046102023000306330ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Either_int32_or_Either_boolean_or_null", "oneOf": [ { "type": "object", "properties": { "Left": { "type": "integer", "format": "int32" } }, "additionalProperties": false, "required": [ "Left" ] }, { "type": "object", "properties": { "Right": { "oneOf": [ { "type": "object", "properties": { "Left": { "type": "boolean" } }, "additionalProperties": false, "required": [ "Left" ] }, { "type": "object", "properties": { "Right": { "type": "null" } }, "additionalProperties": false, "required": [ "Right" ] } ] } }, "additionalProperties": false, "required": [ "Right" ] } ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json000064400000000000000000000003231046102023000320560ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "EnumWithReprAttr", "description": "Description from comment", "type": "integer", "enum": [ 0, 1, 5, 6, 3 ] }././@LongLink00006440000000000000000000000153000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enu000064400000000000000000000072771046102023000325640ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Adjacent", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitOne" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" }, "content": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitStructNewType" }, "content": { "$ref": "#/$defs/UnitStruct" } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" }, "content": { "$ref": "#/$defs/Struct" } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "Struct" }, "content": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "EmptyTuple" }, "content": { "type": "array", "maxItems": 0 } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "Tuple" }, "content": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitAsInt" }, "content": { "type": "integer", "format": "uint64", "minimum": 0 } }, "required": [ "tag", "content" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "TupleAsStr" }, "content": { "type": "string", "pattern": "^\\d+ (true|false)$" } }, "required": [ "tag", "content" ] } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000153000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enu000064400000000000000000000056741046102023000326340ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "oneOf": [ { "type": "string", "enum": [ "unitOne", "unitTwo" ] }, { "type": "object", "properties": { "stringMap": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "stringMap" ], "additionalProperties": false }, { "type": "object", "properties": { "unitStructNewType": { "$ref": "#/$defs/UnitStruct" } }, "required": [ "unitStructNewType" ], "additionalProperties": false }, { "type": "object", "properties": { "structNewType": { "$ref": "#/$defs/Struct" } }, "required": [ "structNewType" ], "additionalProperties": false }, { "type": "object", "properties": { "struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "struct" ], "additionalProperties": false }, { "type": "object", "properties": { "emptyTuple": { "type": "array", "maxItems": 0 } }, "required": [ "emptyTuple" ], "additionalProperties": false }, { "type": "object", "properties": { "tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tuple" ], "additionalProperties": false }, { "type": "object", "properties": { "unitAsInt": { "type": "integer", "format": "uint64", "minimum": 0 } }, "required": [ "unitAsInt" ], "additionalProperties": false }, { "type": "object", "properties": { "tupleAsStr": { "type": "string", "pattern": "^\\d+ (true|false)$" } }, "required": [ "tupleAsStr" ], "additionalProperties": false } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000153000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enu000064400000000000000000000034651046102023000326220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Internal", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitOne" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" } }, "additionalProperties": { "type": "string" }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitStructNewType" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" } }, "$ref": "#/$defs/Struct", "required": [ "tag" ] }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" }, "tag": { "type": "string", "const": "Struct" } }, "required": [ "tag", "foo", "bar" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ "tag" ] } ], "$defs": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~no_variants.json000064400000000000000000000001451046102023000315420ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "NoVariants", "not": {} }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~renamed.json000064400000000000000000000016161046102023000306360ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Renamed", "oneOf": [ { "type": "object", "properties": { "struct_variant": { "type": "object", "properties": { "FIELD": { "type": "string" } }, "required": [ "FIELD" ] } }, "required": [ "struct_variant" ], "additionalProperties": false }, { "type": "object", "properties": { "custom name variant": { "type": "object", "properties": { "custom name field": { "type": "string" } }, "required": [ "custom name field" ] } }, "required": [ "custom name variant" ], "additionalProperties": false } ] }././@LongLink00006440000000000000000000000164000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_doc_comments.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_do000064400000000000000000000006571046102023000326620ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "SoundOfMusic", "oneOf": [ { "title": "A deer", "description": "A female deer", "type": "string", "const": "Do" }, { "description": "A drop of golden sun", "type": "string", "const": "Re" }, { "description": "A name I call myself", "type": "string", "const": "Mi" } ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json000064400000000000000000000026141046102023000320440ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "anyOf": [ { "type": "null" }, { "type": "object", "additionalProperties": { "type": "string" } }, { "$ref": "#/$defs/UnitStruct" }, { "$ref": "#/$defs/Struct" }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, { "type": "array", "maxItems": 0 }, { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }, { "type": "null" }, { "type": "integer", "format": "uint64", "minimum": 0 }, { "type": "string", "pattern": "^\\d+ (true|false)$" } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000156000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_titles.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_ti000064400000000000000000000032471046102023000326260ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "anyOf": [ { "title": "UnitOne", "type": "null" }, { "title": "StringMap", "type": "object", "additionalProperties": { "type": "string" } }, { "title": "UnitStructNewType", "$ref": "#/$defs/UnitStruct" }, { "title": "StructNewType", "$ref": "#/$defs/Struct" }, { "title": "Struct", "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, { "title": "EmptyTuple", "type": "array", "maxItems": 0 }, { "title": "Tuple", "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }, { "title": "UnitTwo", "type": "null" }, { "title": "UnitAsInt", "type": "integer", "format": "uint64", "minimum": 0 }, { "title": "TupleAsStr", "type": "string", "pattern": "^\\d+ (true|false)$" } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000177000000000000010000Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~a000064400000000000000000000051411046102023000326140ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Adjacent", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "Unit" } }, "required": [ "tag" ], "additionalProperties": false }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" }, "content": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "tag", "content" ], "additionalProperties": false }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" }, "content": { "$ref": "#/$defs/Struct" } }, "required": [ "tag", "content" ], "additionalProperties": false }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StructDenyUnknownFieldsNewType" }, "content": { "$ref": "#/$defs/StructDenyUnknownFields" } }, "required": [ "tag", "content" ], "additionalProperties": false }, { "type": "object", "properties": { "tag": { "type": "string", "const": "Struct" }, "content": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "foo", "bar" ] } }, "required": [ "tag", "content" ], "additionalProperties": false } ], "$defs": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "StructDenyUnknownFields": { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "baz", "foobar" ] } } }././@LongLink00006440000000000000000000000177000000000000010000Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~e000064400000000000000000000041271046102023000326230ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "oneOf": [ { "type": "string", "enum": [ "Unit" ] }, { "type": "object", "properties": { "StringMap": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "StringMap" ], "additionalProperties": false }, { "type": "object", "properties": { "StructNewType": { "$ref": "#/$defs/Struct" } }, "required": [ "StructNewType" ], "additionalProperties": false }, { "type": "object", "properties": { "StructDenyUnknownFieldsNewType": { "$ref": "#/$defs/StructDenyUnknownFields" } }, "required": [ "StructDenyUnknownFieldsNewType" ], "additionalProperties": false }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ], "additionalProperties": false } ], "$defs": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "StructDenyUnknownFields": { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "baz", "foobar" ] } } }././@LongLink00006440000000000000000000000177000000000000010000Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~i000064400000000000000000000036351046102023000326320ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Internal", "oneOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "Unit" } }, "required": [ "tag" ], "additionalProperties": false }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" } }, "additionalProperties": { "type": "string" }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" } }, "$ref": "#/$defs/Struct", "required": [ "tag" ] }, { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" }, "tag": { "type": "string", "const": "StructDenyUnknownFieldsNewType" } }, "additionalProperties": false, "required": [ "tag", "baz", "foobar" ] }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" }, "tag": { "type": "string", "const": "Struct" } }, "additionalProperties": false, "required": [ "tag", "foo", "bar" ] } ], "$defs": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000166000000000000007776Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~u000064400000000000000000000023711046102023000326420ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "anyOf": [ { "type": "null" }, { "type": "object", "additionalProperties": { "type": "string" } }, { "$ref": "#/$defs/Struct" }, { "$ref": "#/$defs/StructDenyUnknownFields" }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "foo", "bar" ] } ], "$defs": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "StructDenyUnknownFields": { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "baz", "foobar" ] } } }././@LongLink00006440000000000000000000000167000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~adjacent_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~adjacent_en000064400000000000000000000070371046102023000325370ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AdjacentContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "oneOf": [ { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit1" } }, "required": [ "tag1" ] }, { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit2" } }, "required": [ "tag1" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" }, "content2": true }, "required": [ "tag2", "content2" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "Int" }, "content3": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "tag3", "content3" ] }, { "type": "object", "properties": { "tag3": { "type": "string", "const": "Tuple" }, "content3": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag3", "content3" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "tag4": { "type": "string", "const": "StructNewType" }, "content4": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "tag4", "content4" ] }, { "type": "object", "properties": { "tag4": { "type": "string", "const": "Struct" }, "content4": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "tag4", "content4" ] } ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000167000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_en000064400000000000000000000055271046102023000326120ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "Tuple" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000213000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_enums_flattened_deny_unknown_fields.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_en000064400000000000000000000056121046102023000326050ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalContainerDenyUnknownFields", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "unevaluatedProperties": false, "allOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "Tuple" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000223000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_enums_flattened_deny_unknown_fields_draft07.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~external_en000064400000000000000000000060601046102023000326030ustar 00000000000000{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExternalContainerDenyUnknownFields", "type": "object", "properties": { "f": { "type": "number", "format": "float" }, "Int": true, "Struct": true, "StructNewType": true, "Tuple": true, "Unit1": true, "Unit2": true, "Unit3": true, "ValueNewType": true }, "required": [ "f" ], "allOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ] } }, "required": [ "Tuple" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/definitions/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] } ], "additionalProperties": false, "definitions": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000167000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~internal_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~internal_en000064400000000000000000000037041046102023000325770ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "InternalContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "oneOf": [ { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit1" } }, "required": [ "tag1" ] }, { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit2" } }, "required": [ "tag1" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" } }, "required": [ "tag2" ] } ] } ], "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "StructNewType" } }, "$ref": "#/$defs/EmptyStruct", "required": [ "tag3" ] }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" }, "tag3": { "type": "string", "const": "Struct" } }, "required": [ "tag3", "foo", "bar" ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000164000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~mixed_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~mixed_enums000064400000000000000000000047501046102023000326200ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MixedContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" } }, "required": [ "tag2" ] } ] } ], "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "Int" }, "content3": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "tag3", "content3" ] }, { "type": "object", "properties": { "tag3": { "type": "string", "const": "Tuple" }, "content3": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag3", "content3" ] } ], "anyOf": [ { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" } }, "required": [ "foo" ] }, { "type": "object", "properties": { "bar": { "type": "boolean" } }, "required": [ "bar" ] }, true ] }././@LongLink00006440000000000000000000000167000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~untagged_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~untagged_en000064400000000000000000000011521046102023000325540ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UntaggedContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "anyOf": [ { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" } }, "required": [ "foo" ] }, { "type": "object", "properties": { "bar": { "type": "boolean" } }, "required": [ "bar" ] }, true ] }././@LongLink00006440000000000000000000000176000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~adjacent_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~adja000064400000000000000000000105331046102023000325660ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AdjacentContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit1" } }, "required": [ "tag1" ] }, { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit2" } }, "required": [ "tag1" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" }, "content2": true }, "required": [ "tag2", "content2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "Int" }, "content3": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "tag3", "content3" ] }, { "type": "object", "properties": { "tag3": { "type": "string", "const": "Tuple" }, "content3": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag3", "content3" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag4": { "type": "string", "const": "StructNewType" }, "content4": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "tag4", "content4" ] }, { "type": "object", "properties": { "tag4": { "type": "string", "const": "Struct" }, "content4": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "tag4", "content4" ] } ] }, {} ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000176000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~external_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~exte000064400000000000000000000070431046102023000326360ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "Tuple" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] }, {} ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000222000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~external_enums_flattened_deny_unknown_fields.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~exte000064400000000000000000000071261046102023000326400ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalContainerDenyUnknownFields", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "unevaluatedProperties": false, "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "Tuple" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/$defs/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] }, {} ] } ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000232000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~external_enums_flattened_deny_unknown_fields_draft07.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~exte000064400000000000000000000073741046102023000326450ustar 00000000000000{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "ExternalContainerDenyUnknownFields", "type": "object", "properties": { "f": { "type": "number", "format": "float" }, "Int": true, "Struct": true, "StructNewType": true, "Tuple": true, "Unit1": true, "Unit2": true, "Unit3": true, "ValueNewType": true }, "required": [ "f" ], "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ] }, { "type": "object", "properties": { "Unit3": { "type": "null" } }, "required": [ "Unit3" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Int": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "Int" ] }, { "type": "object", "properties": { "Tuple": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ] } }, "required": [ "Tuple" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "StructNewType": { "$ref": "#/definitions/EmptyStruct" } }, "required": [ "StructNewType" ] }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "Struct" ] } ] }, {} ] } ], "additionalProperties": false, "definitions": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000176000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~internal_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~inte000064400000000000000000000046731046102023000326360ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "InternalContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit1" } }, "required": [ "tag1" ] }, { "type": "object", "properties": { "tag1": { "type": "string", "const": "Unit2" } }, "required": [ "tag1" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" } }, "required": [ "tag2" ] } ] }, {} ] } ], "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "StructNewType" } }, "$ref": "#/$defs/EmptyStruct", "required": [ "tag3" ] }, { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" }, "tag3": { "type": "string", "const": "Struct" } }, "required": [ "tag3", "foo", "bar" ] } ] }, {} ], "$defs": { "EmptyStruct": { "type": "object" } } }././@LongLink00006440000000000000000000000173000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~mixed_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~mixe000064400000000000000000000065571046102023000326440ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MixedContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "allOf": [ { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "Unit1": { "type": "null" } }, "required": [ "Unit1" ] }, { "type": "object", "properties": { "Unit2": { "type": "null" } }, "required": [ "Unit2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag2": { "type": "string", "const": "Unit3" } }, "required": [ "tag2" ] }, { "type": "object", "properties": { "tag2": { "type": "string", "const": "ValueNewType" } }, "required": [ "tag2" ] } ] }, {} ] }, { "anyOf": [ { "oneOf": [ { "type": "object", "properties": { "tag3": { "type": "string", "const": "Int" }, "content3": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "tag3", "content3" ] }, { "type": "object", "properties": { "tag3": { "type": "string", "const": "Tuple" }, "content3": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag3", "content3" ] } ] }, {} ] }, { "anyOf": [ { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" } }, "required": [ "foo" ] }, { "type": "object", "properties": { "bar": { "type": "boolean" } }, "required": [ "bar" ] }, true, {} ] } ] }././@LongLink00006440000000000000000000000176000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~untagged_enums_flattened.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_option_flattened.rs~unta000064400000000000000000000011621046102023000326340ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UntaggedContainer", "type": "object", "properties": { "f": { "type": "number", "format": "float" } }, "required": [ "f" ], "anyOf": [ { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" } }, "required": [ "foo" ] }, { "type": "object", "properties": { "bar": { "type": "boolean" } }, "required": [ "bar" ] }, true, {} ] }././@LongLink00006440000000000000000000000170000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~adjacently_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~adjacent000064400000000000000000000076661046102023000326020ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Adjacent", "oneOf": [ { "$ref": "#/$defs/UnitOne" }, { "$ref": "#/$defs/StringMap" }, { "$ref": "#/$defs/UnitStructNewType" }, { "$ref": "#/$defs/StructNewType" }, { "$ref": "#/$defs/Struct2" }, { "$ref": "#/$defs/Tuple" }, { "$ref": "#/$defs/UnitTwo" }, { "$ref": "#/$defs/UnitAsInt" }, { "$ref": "#/$defs/TupleAsStr" } ], "$defs": { "UnitOne": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitOne" } }, "required": [ "tag" ] }, "StringMap": { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" }, "content": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "tag", "content" ] }, "UnitStructNewType": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitStructNewType" }, "content": { "$ref": "#/$defs/UnitStruct" } }, "required": [ "tag", "content" ] }, "UnitStruct": { "type": "null" }, "StructNewType": { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" }, "content": { "$ref": "#/$defs/Struct" } }, "required": [ "tag", "content" ] }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "Struct2": { "type": "object", "properties": { "tag": { "type": "string", "const": "Struct" }, "content": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "tag", "content" ] }, "Tuple": { "type": "object", "properties": { "tag": { "type": "string", "const": "Tuple" }, "content": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tag", "content" ] }, "UnitTwo": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ "tag" ] }, "UnitAsInt": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitAsInt" }, "content": { "type": "integer", "format": "uint64", "minimum": 0 } }, "required": [ "tag", "content" ] }, "TupleAsStr": { "type": "object", "properties": { "tag": { "type": "string", "const": "TupleAsStr" }, "content": { "type": "string", "pattern": "^\\d+ (true|false)$" } }, "required": [ "tag", "content" ] } } }././@LongLink00006440000000000000000000000170000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~externally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~external000064400000000000000000000064071046102023000326430ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "oneOf": [ { "$ref": "#/$defs/unitOne" }, { "$ref": "#/$defs/stringMap" }, { "$ref": "#/$defs/unitStructNewType" }, { "$ref": "#/$defs/structNewType" }, { "$ref": "#/$defs/struct" }, { "$ref": "#/$defs/tuple" }, { "$ref": "#/$defs/unitTwo" }, { "$ref": "#/$defs/unitAsInt" }, { "$ref": "#/$defs/tupleAsStr" } ], "$defs": { "unitOne": { "type": "string", "const": "unitOne" }, "stringMap": { "type": "object", "properties": { "stringMap": { "type": "object", "additionalProperties": { "type": "string" } } }, "required": [ "stringMap" ], "additionalProperties": false }, "unitStructNewType": { "type": "object", "properties": { "unitStructNewType": { "$ref": "#/$defs/UnitStruct" } }, "required": [ "unitStructNewType" ], "additionalProperties": false }, "UnitStruct": { "type": "null" }, "structNewType": { "type": "object", "properties": { "structNewType": { "$ref": "#/$defs/Struct" } }, "required": [ "structNewType" ], "additionalProperties": false }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "struct": { "type": "object", "properties": { "struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } }, "required": [ "struct" ], "additionalProperties": false }, "tuple": { "type": "object", "properties": { "tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "tuple" ], "additionalProperties": false }, "unitTwo": { "type": "string", "const": "unitTwo" }, "unitAsInt": { "type": "object", "properties": { "unitAsInt": { "type": "integer", "format": "uint64", "minimum": 0 } }, "required": [ "unitAsInt" ], "additionalProperties": false }, "tupleAsStr": { "type": "object", "properties": { "tupleAsStr": { "type": "string", "pattern": "^\\d+ (true|false)$" } }, "required": [ "tupleAsStr" ], "additionalProperties": false } } }././@LongLink00006440000000000000000000000170000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~internally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~internal000064400000000000000000000042511046102023000326300ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Internal", "oneOf": [ { "$ref": "#/$defs/UnitOne" }, { "$ref": "#/$defs/StringMap" }, { "$ref": "#/$defs/UnitStructNewType" }, { "$ref": "#/$defs/StructNewType" }, { "$ref": "#/$defs/Struct2" }, { "$ref": "#/$defs/UnitTwo" } ], "$defs": { "UnitOne": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitOne" } }, "required": [ "tag" ] }, "StringMap": { "type": "object", "properties": { "tag": { "type": "string", "const": "StringMap" } }, "additionalProperties": { "type": "string" }, "required": [ "tag" ] }, "UnitStructNewType": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitStructNewType" } }, "required": [ "tag" ] }, "StructNewType": { "type": "object", "properties": { "tag": { "type": "string", "const": "StructNewType" } }, "$ref": "#/$defs/Struct", "required": [ "tag" ] }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "Struct2": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" }, "tag": { "type": "string", "const": "Struct" } }, "required": [ "tag", "foo", "bar" ] }, "UnitTwo": { "type": "object", "properties": { "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ "tag" ] } } }././@LongLink00006440000000000000000000000155000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~no_variants.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~no_varia000064400000000000000000000001451046102023000326100ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "NoVariants", "not": {} }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~renamed.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~renamed.000064400000000000000000000020711046102023000325030ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Renamed", "oneOf": [ { "$ref": "#/$defs/struct_variant" }, { "$ref": "#/$defs/custom%20name%20variant" } ], "$defs": { "struct_variant": { "type": "object", "properties": { "struct_variant": { "type": "object", "properties": { "FIELD": { "type": "string" } }, "required": [ "FIELD" ] } }, "required": [ "struct_variant" ], "additionalProperties": false }, "custom name variant": { "type": "object", "properties": { "custom name variant": { "type": "object", "properties": { "custom name field": { "type": "string" } }, "required": [ "custom name field" ] } }, "required": [ "custom name variant" ], "additionalProperties": false } } }././@LongLink00006440000000000000000000000157000000000000007776Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~untagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_ref_variants.rs~untagged000064400000000000000000000035661046102023000326220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Untagged", "anyOf": [ { "$ref": "#/$defs/UnitOne" }, { "$ref": "#/$defs/StringMap" }, { "$ref": "#/$defs/UnitStructNewType" }, { "$ref": "#/$defs/StructNewType" }, { "$ref": "#/$defs/Struct2" }, { "$ref": "#/$defs/Tuple" }, { "$ref": "#/$defs/UnitTwo" }, { "$ref": "#/$defs/UnitAsInt" }, { "$ref": "#/$defs/TupleAsStr" } ], "$defs": { "UnitOne": { "type": "null" }, "StringMap": { "type": "object", "additionalProperties": { "type": "string" } }, "UnitStructNewType": { "$ref": "#/$defs/UnitStruct" }, "UnitStruct": { "type": "null" }, "StructNewType": { "$ref": "#/$defs/Struct" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "Struct2": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }, "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }, "UnitTwo": { "type": "null" }, "UnitAsInt": { "type": "integer", "format": "uint64", "minimum": 0 }, "TupleAsStr": { "type": "string", "pattern": "^\\d+ (true|false)$" } } }././@LongLink00006440000000000000000000000174000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~adjacently_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~adja000064400000000000000000000036251046102023000325560ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Adjacent", "anyOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "TaggedUnitOne" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "tag": { "type": "string", "const": "TaggedStruct" }, "content": { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "required": [ "baz", "foobar" ] } }, "required": [ "tag", "content" ] }, { "type": "null" }, { "$ref": "#/$defs/UnitStruct" }, { "$ref": "#/$defs/Struct" }, { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "required": [ "baz", "foobar" ] }, { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }, { "type": "object", "additionalProperties": { "type": "string" } } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000174000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~externally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~exte000064400000000000000000000033501046102023000326170ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "anyOf": [ { "type": "string", "enum": [ "taggedUnitOne" ] }, { "type": "object", "properties": { "taggedStruct": { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "required": [ "baz", "foobar" ] } }, "required": [ "taggedStruct" ], "additionalProperties": false }, { "type": "null" }, { "$ref": "#/$defs/UnitStruct" }, { "$ref": "#/$defs/Struct" }, { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "required": [ "baz", "foobar" ] }, { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }, { "type": "object", "additionalProperties": { "type": "string" } } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }././@LongLink00006440000000000000000000000174000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~internally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/enums_untagged_variant.rs~inte000064400000000000000000000027561046102023000326220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Internal", "anyOf": [ { "type": "object", "properties": { "tag": { "type": "string", "const": "TaggedUnitOne" } }, "required": [ "tag" ] }, { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" }, "tag": { "type": "string", "const": "TaggedStruct" } }, "required": [ "tag", "baz", "foobar" ] }, { "type": "null" }, { "$ref": "#/$defs/UnitStruct" }, { "$ref": "#/$defs/Struct" }, { "type": "object", "properties": { "baz": { "type": "integer", "format": "int32" }, "foobar": { "type": "boolean" } }, "required": [ "baz", "foobar" ] }, { "type": "object", "additionalProperties": { "type": "string" } } ], "$defs": { "UnitStruct": { "type": "null" }, "Struct": { "type": "object", "properties": { "foo": { "type": "integer", "format": "int32" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json000064400000000000000000000010651046102023000321150ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "foo": { "type": "integer", "format": "int32", "examples": [ 8, null ] }, "bar": { "type": "boolean" }, "baz": { "type": [ "string", "null" ], "examples": [ null, "foo" ] } }, "required": [ "foo", "bar" ], "examples": [ { "foo": 0, "bar": false, "baz": null }, null ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json000064400000000000000000000011001046102023000323040ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "foo": { "type": "integer", "format": "int32", "examples": [ 8, null ] }, "bar": { "type": "boolean" }, "baz": { "type": [ "string", "null" ], "examples": [ null, "foo" ] } }, "required": [ "foo", "bar", "baz" ], "examples": [ { "foo": 0, "bar": false, "baz": null }, null ] }././@LongLink00006440000000000000000000000163000000000000007773Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_ta000064400000000000000000000031451046102023000325630ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AdjacentEnum", "oneOf": [ { "type": "object", "properties": { "t": { "type": "string", "const": "Unit" } }, "required": [ "t" ], "foo": "bar" }, { "type": "object", "properties": { "t": { "type": "string", "const": "NewType" }, "c": true }, "required": [ "t", "c" ], "foo": "bar" }, { "type": "object", "properties": { "t": { "type": "string", "const": "Tuple" }, "c": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "t", "c" ], "foo": "bar" }, { "type": "object", "properties": { "t": { "type": "string", "const": "Struct" }, "c": { "type": "object", "properties": { "i": { "type": "integer", "format": "int32" }, "b": { "type": "boolean" } }, "required": [ "i", "b" ] } }, "required": [ "t", "c" ], "foo": "bar" } ], "foo": "bar" }././@LongLink00006440000000000000000000000163000000000000007773Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_ta000064400000000000000000000025251046102023000326350ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ExternalEnum", "oneOf": [ { "type": "string", "const": "Unit", "foo": "bar" }, { "type": "object", "properties": { "NewType": true }, "required": [ "NewType" ], "additionalProperties": false, "foo": "bar" }, { "type": "object", "properties": { "Tuple": { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 } }, "required": [ "Tuple" ], "additionalProperties": false, "foo": "bar" }, { "type": "object", "properties": { "Struct": { "type": "object", "properties": { "i": { "type": "integer", "format": "int32" }, "b": { "type": "boolean" } }, "required": [ "i", "b" ] } }, "required": [ "Struct" ], "additionalProperties": false, "foo": "bar" } ], "foo": "bar" }././@LongLink00006440000000000000000000000163000000000000007773Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_ta000064400000000000000000000016201046102023000326220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "InternalEnum", "oneOf": [ { "type": "object", "properties": { "t": { "type": "string", "const": "Unit" } }, "required": [ "t" ], "foo": "bar" }, { "type": "object", "properties": { "t": { "type": "string", "const": "NewType" } }, "required": [ "t" ], "foo": "bar" }, { "type": "object", "properties": { "i": { "type": "integer", "format": "int32" }, "b": { "type": "boolean" }, "t": { "type": "string", "const": "Struct" } }, "required": [ "t", "i", "b" ], "foo": "bar" } ], "foo": "bar" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json000064400000000000000000000006211046102023000322510ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "value": { "foo": "bar" }, "int": { "type": [ "number", "string" ], "format": "int32" } }, "required": [ "value", "int" ], "obj": { "array": [ null, null ] }, "3": 3.0, "pi": 3.14 }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.000064400000000000000000000006171046102023000325750ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TupleStruct", "type": "array", "prefixItems": [ { "foo": "bar" }, { "type": [ "number", "string" ], "format": "uint", "minimum": 0 } ], "minItems": 2, "maxItems": 2, "obj": { "array": [ null, null ] }, "3": 3.0, "pi": 3.14 }././@LongLink00006440000000000000000000000152000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum000064400000000000000000000013451046102023000326030ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UntaggedEnum", "anyOf": [ { "type": "null", "foo": "bar" }, { "foo": "bar" }, { "type": "array", "prefixItems": [ { "type": "integer", "format": "int32" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2, "foo": "bar" }, { "type": "object", "properties": { "i": { "type": "integer", "format": "int32" }, "b": { "type": "boolean" } }, "required": [ "i", "b" ], "foo": "bar" } ], "foo": "bar" }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.js000064400000000000000000000006671046102023000325530ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Flat", "type": "object", "properties": { "f": { "type": "number", "format": "float" }, "b": { "type": "boolean" }, "s": { "type": "string" }, "v": { "type": "array", "items": { "type": "integer", "format": "int32" } } }, "required": [ "f", "b", "v" ] }././@LongLink00006440000000000000000000000146000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.jso000064400000000000000000000003611046102023000325110ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "FlattenValue", "type": "object", "properties": { "flag": { "type": "boolean" } }, "required": [ "flag" ], "additionalProperties": true }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_into.rs~from.de.json000064400000000000000000000002031046102023000314110ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ClampingI8", "type": "integer", "format": "int128" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_into.rs~from.ser.json000064400000000000000000000002461046102023000316210ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ClampingI8", "type": "integer", "format": "int8", "minimum": -128, "maximum": 127 }././@LongLink00006440000000000000000000000152000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_into.rs~into_and_try_from.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_into.rs~into_and_try_from000064400000000000000000000002551046102023000326320ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "EventSequenceNumber", "type": "string", "pattern": "^[0-9a-f]{16}:[0-9a-f]{16}:[0-9a-f]{4}$" }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.js000064400000000000000000000027241046102023000326150ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { "myInt": { "type": "integer" }, "myBool": { "type": "boolean" }, "myNullableEnum": true, "myInnerStruct": { "type": "object", "properties": { "my_map": { "type": "object", "additionalProperties": { "type": "number" } }, "my_vec": { "type": "array", "items": { "type": "number" } }, "my_empty_map": { "type": "object", "additionalProperties": true }, "my_empty_vec": { "type": "array", "items": true }, "my_tuple": { "type": "array", "prefixItems": [ { "type": "string", "minLength": 1, "maxLength": 1 }, { "type": "integer" } ], "maxItems": 2, "minItems": 2 } } } }, "examples": [ { "myInt": 123, "myBool": true, "myNullableEnum": null, "myInnerStruct": { "my_map": { "k": 1.23 }, "my_vec": [ 1.0, 2.0, 3.0 ], "my_empty_map": {}, "my_empty_vec": [], "my_tuple": [ "💩", 42 ] } } ] }././@LongLink00006440000000000000000000000160000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_op000064400000000000000000000026621046102023000327010ustar 00000000000000{ "$schema": "https://spec.openapis.org/oas/3.0/schema/2024-10-18#/definitions/Schema", "title": "MyStruct", "type": "object", "properties": { "myInt": { "type": "integer" }, "myBool": { "type": "boolean" }, "myNullableEnum": {}, "myInnerStruct": { "type": "object", "properties": { "my_map": { "type": "object", "additionalProperties": { "type": "number" } }, "my_vec": { "type": "array", "items": { "type": "number" } }, "my_empty_map": { "type": "object", "additionalProperties": true }, "my_empty_vec": { "type": "array", "items": {} }, "my_tuple": { "type": "array", "minItems": 2, "maxItems": 2, "items": [ { "type": "string", "minLength": 1, "maxLength": 1 }, { "type": "integer" } ] } } } }, "example": { "myInt": 123, "myBool": true, "myNullableEnum": null, "myInnerStruct": { "my_map": { "k": 1.23 }, "my_vec": [ 1.0, 2.0, 3.0 ], "my_empty_map": {}, "my_empty_vec": [], "my_tuple": [ "💩", 42 ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json000064400000000000000000000017351046102023000324020ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "zero": { "type": "integer" }, "zeroPointZero": { "type": "number" }, "bool": { "type": "boolean" }, "null": true, "object": { "type": "object", "properties": { "strings": { "type": "array", "items": { "type": "string" } }, "mixed": { "type": "array", "items": { "anyOf": [ { "type": "integer" }, { "type": "boolean" } ] } } } } }, "examples": [ { "zero": 0, "zeroPointZero": 0.0, "bool": true, "null": null, "object": { "strings": [ "foo", "bar" ], "mixed": [ 1, true ] } } ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json000064400000000000000000000024321046102023000314520ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "GardeAttrStruct", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", "minimum": 1.0, "maximum": 100.0 }, "min_max2": { "type": "number", "format": "float", "minimum": 1.0, "maximum": 10.0 }, "regex_str": { "type": "string", "pattern": "^[Hh]ello" }, "contains_str": { "type": "string", "pattern": "substring\\.\\.\\." }, "email_address": { "type": "string", "format": "email" }, "homepage": { "type": "string", "format": "uri" }, "non_empty_str": { "type": "string", "minLength": 1, "maxLength": 10 }, "pair": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 2, "maxItems": 2 }, "required_option": { "type": "boolean" }, "x": { "type": "integer", "format": "int32", "minimum": -100, "maximum": 100 } }, "required": [ "min_max", "min_max2", "regex_str", "contains_str", "email_address", "homepage", "non_empty_str", "pair", "required_option", "x" ] }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.j000064400000000000000000000002511046102023000325020ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "GardeAttrNewType", "type": "integer", "format": "uint8", "minimum": 0, "maximum": 10 }././@LongLink00006440000000000000000000000146000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.jso000064400000000000000000000004641046102023000325100ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "GardeAttrTuple", "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 10 }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }././@LongLink00006440000000000000000000000156000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_normal.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_no000064400000000000000000000006121046102023000326320ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyJob", "type": "object", "properties": { "spec": { "type": "object", "properties": { "replicas": { "type": "integer", "format": "uint32", "minimum": 0 } }, "required": [ "replicas" ] } }, "required": [ "spec" ] }././@LongLink00006440000000000000000000000164000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_re000064400000000000000000000007471046102023000326350ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "RecursiveOuter", "type": "object", "properties": { "direct": { "anyOf": [ { "$ref": "#" }, { "type": "null" } ] }, "indirect": { "type": [ "object", "null" ], "properties": { "recursive": { "$ref": "#" } }, "required": [ "recursive" ] } } }././@LongLink00006440000000000000000000000165000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_re000064400000000000000000000010311046102023000326200ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "RecursiveOuter", "type": "object", "properties": { "direct": { "anyOf": [ { "$ref": "#" }, { "type": "null" } ] }, "indirect": { "type": [ "object", "null" ], "properties": { "recursive": { "$ref": "#" } }, "required": [ "recursive" ] } }, "required": [ "direct", "indirect" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/jiff.rs~jiff.json000064400000000000000000000015161046102023000277270ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "JiffTypes", "type": "object", "properties": { "date_time_ts": { "type": "string", "format": "date-time" }, "date_time_zoned": { "type": "string", "format": "zoned-date-time" }, "naive_date": { "type": "string", "format": "date" }, "naive_date_time": { "type": "string", "format": "partial-date-time" }, "naive_time": { "type": "string", "format": "partial-time" }, "duration": { "type": "string", "format": "duration" }, "span": { "type": "string", "format": "duration" } }, "required": [ "date_time_ts", "date_time_zoned", "naive_date", "naive_date_time", "naive_time", "duration", "span" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/map.rs~maps.json000064400000000000000000000024511046102023000276070ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Maps", "type": "object", "properties": { "s_map": { "type": "object", "additionalProperties": { "type": "boolean" } }, "i_map": { "type": "object", "additionalProperties": false, "patternProperties": { "^-?\\d+$": { "type": "boolean" } } }, "u_map": { "type": "object", "additionalProperties": false, "patternProperties": { "^\\d+$": { "type": "boolean" } } }, "pattern_map": { "type": "object", "additionalProperties": false, "patternProperties": { "^[0-9a-f]*$": { "type": "boolean" } } }, "enum_map": { "type": "object", "properties": { "Unit1": { "type": "boolean" }, "Unit2": { "type": "boolean" } }, "additionalProperties": false, "patternProperties": { "^-?\\d+$": { "type": "boolean" } } } }, "required": [ "s_map", "i_map", "u_map", "pattern_map", "enum_map" ], "$defs": { "IndirectU32": { "type": "integer", "format": "uint32", "minimum": 0 } } }././@LongLink00006440000000000000000000000153000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_param.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_para000064400000000000000000000004141046102023000325510ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "LifetimeParam", "type": "object", "properties": { "s": { "$ref": "#/$defs/Str" } }, "required": [ "s" ], "$defs": { "Str": { "type": "string" } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json000064400000000000000000000010501046102023000322060ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Process", "type": "object", "properties": { "wall_time": { "$ref": "#/$defs/Duration" } }, "required": [ "wall_time" ], "$defs": { "Duration": { "type": "object", "properties": { "secs": { "type": "integer", "format": "int64" }, "nanos": { "type": "integer", "format": "int32" } }, "required": [ "secs", "nanos" ] } } }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.js000064400000000000000000000013211046102023000325220ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TypeParam", "type": "object", "properties": { "byte_or_bool": { "$ref": "#/$defs/uint8_or_boolean" }, "unit_or_t": { "$ref": "#/$defs/null_or_string" } }, "required": [ "byte_or_bool", "unit_or_t" ], "$defs": { "uint8_or_boolean": { "anyOf": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "boolean" } ] }, "null_or_string": { "anyOf": [ { "type": "null" }, { "type": "string" } ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json000064400000000000000000000016021046102023000317410ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Config2", "type": "object", "properties": { "a_cfg": { "$ref": "#/$defs/Config" }, "b_cfg": { "$ref": "#/$defs/Config2" }, "c_cfg": { "$ref": "#/$defs/Config3" } }, "required": [ "a_cfg", "b_cfg", "c_cfg" ], "$defs": { "Config": { "type": "object", "properties": { "test": { "type": "string" } }, "required": [ "test" ] }, "Config2": { "type": "object", "properties": { "test2": { "type": "string" } }, "required": [ "test2" ] }, "Config3": { "type": "object", "properties": { "test3": { "type": "string" } }, "required": [ "test3" ] } } }././@LongLink00006440000000000000000000000160000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~container_schema_with.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~container_schem000064400000000000000000000002061046102023000325520ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "IntAsString", "type": "string", "pattern": "^-?\\d+$" }././@LongLink00006440000000000000000000000162000000000000007772Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~container_with_metadata.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~container_with_000064400000000000000000000006341046102023000325720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct3", "description": "Testing...", "type": "object", "properties": { "x": { "type": "string", "pattern": "^-?\\d+$" }, "t": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "examples": [ "" ] } }, "required": [ "x", "t" ] }././@LongLink00006440000000000000000000000154000000000000007773Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~field_schema_with.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~field_schema_wi000064400000000000000000000005741046102023000325230ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "x": { "type": "string", "pattern": "^-?\\d+$" }, "t": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "string", "examples": [ "" ] } }, "required": [ "x", "t" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/semver.rs~semver.json000064400000000000000000000004701046102023000306730ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "SemVer", "type": "string", "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json000064400000000000000000000032131046102023000315650ustar 00000000000000{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/definitions/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/definitions/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "values", "value", "inner", "tuples" ], "definitions": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.ser.json000064400000000000000000000032571046102023000317760ustar 00000000000000{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/definitions/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/definitions/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "maybe_int", "values", "value", "inner", "maybe_inner", "tuples" ], "definitions": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.js000064400000000000000000000031761046102023000317150ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/$defs/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/$defs/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "values", "value", "inner", "tuples" ], "$defs": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.j000064400000000000000000000032421046102023000317250ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/$defs/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/$defs/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "maybe_int", "values", "value", "inner", "maybe_inner", "tuples" ], "$defs": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.js000064400000000000000000000032041046102023000316670ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/$defs/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/$defs/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ], "minItems": 2, "maxItems": 2 } } }, "required": [ "values", "value", "inner", "tuples" ], "$defs": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }././@LongLink00006440000000000000000000000150000000000000007767Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.j000064400000000000000000000032501046102023000317060ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": [ "integer", "null" ], "format": "int32", "examples": [ 8, null ] }, "values": { "type": "object", "additionalProperties": true }, "value": true, "inner": { "$ref": "#/$defs/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/$defs/InnerEnum" }, { "type": "null" } ] }, "tuples": { "type": "array", "items": { "type": "array", "prefixItems": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ], "minItems": 2, "maxItems": 2 } } }, "required": [ "maybe_int", "values", "value", "inner", "maybe_inner", "tuples" ], "$defs": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "const": "DocumentedUnit" }, { "type": "object", "properties": { "ValueNewType": true }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json000064400000000000000000000034451046102023000320430ustar 00000000000000{ "$schema": "https://spec.openapis.org/oas/3.0/schema/2024-10-18#/definitions/Schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": "integer", "format": "int32", "nullable": true, "example": 8 }, "values": { "type": "object", "additionalProperties": true }, "value": {}, "inner": { "$ref": "#/components/schemas/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/components/schemas/InnerEnum" }, { "nullable": true, "enum": [ null ] } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "values", "value", "inner", "tuples" ], "components": { "schemas": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "enum": [ "DocumentedUnit" ] }, { "type": "object", "properties": { "ValueNewType": {} }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.ser.json000064400000000000000000000035111046102023000322360ustar 00000000000000{ "$schema": "https://spec.openapis.org/oas/3.0/schema/2024-10-18#/definitions/Schema", "title": "OuterStruct", "type": "object", "properties": { "maybe_int": { "type": "integer", "format": "int32", "nullable": true, "example": 8 }, "values": { "type": "object", "additionalProperties": true }, "value": {}, "inner": { "$ref": "#/components/schemas/InnerEnum" }, "maybe_inner": { "anyOf": [ { "$ref": "#/components/schemas/InnerEnum" }, { "nullable": true, "enum": [ null ] } ] }, "tuples": { "type": "array", "items": { "type": "array", "maxItems": 2, "minItems": 2, "items": [ { "type": "integer", "format": "uint8", "minimum": 0, "maximum": 255 }, { "type": "integer", "format": "int64" } ] } } }, "required": [ "maybe_int", "values", "value", "inner", "maybe_inner", "tuples" ], "components": { "schemas": { "InnerEnum": { "oneOf": [ { "type": "string", "enum": [ "UndocumentedUnit1", "UndocumentedUnit2" ] }, { "description": "This is a documented unit variant", "type": "string", "enum": [ "DocumentedUnit" ] }, { "type": "object", "properties": { "ValueNewType": {} }, "required": [ "ValueNewType" ], "additionalProperties": false } ] } } } }././@LongLink00006440000000000000000000000146000000000000007774Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.jso000064400000000000000000000002301046102023000325540ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Enum", "type": "string", "enum": [ "Included1", "Included2" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json000064400000000000000000000003641046102023000325560ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "included": { "type": "boolean" } }, "additionalProperties": false, "required": [ "included" ] }././@LongLink00006440000000000000000000000152000000000000007771Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields000064400000000000000000000004531046102023000326750ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "DenyUnknownFields", "type": "object", "properties": { "foo": { "type": "string" }, "bar": { "type": "boolean" } }, "additionalProperties": false, "required": [ "foo", "bar" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json000064400000000000000000000001511046102023000312670ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "NewType", "type": "string" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json000064400000000000000000000004051046102023000310660ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "NormalStruct", "type": "object", "properties": { "foo": { "type": "string" }, "bar": { "type": "boolean" } }, "required": [ "foo", "bar" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~property_order.json000064400000000000000000000022721046102023000326610ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "PropertyOrder", "type": "object", "properties": { "$defs": { "$ref": "#/$defs/UnitStruct" }, "examples": { "$ref": "#/$defs/UnitStruct" }, "properties": { "$ref": "#/$defs/UnitStruct" }, "required": { "$ref": "#/$defs/UnitStruct" }, "$schema": { "$ref": "#/$defs/UnitStruct" }, "title": { "$ref": "#/$defs/UnitStruct" }, "type": { "$ref": "#/$defs/UnitStruct" }, "x-custom": { "$ref": "#/$defs/UnitStruct" } }, "required": [ "$defs", "examples", "properties", "required", "$schema", "title", "type", "x-custom" ], "examples": [ { "$defs": null, "examples": null, "properties": null, "required": null, "$schema": null, "title": null, "type": null, "x-custom": null } ], "x-custom": { "$defs": null, "examples": null, "properties": null, "required": null, "$schema": null, "title": null, "type": null, "x-custom": null }, "$defs": { "UnitStruct": { "type": "null" } } }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json000064400000000000000000000005171046102023000325430ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "RenamedFields", "type": "object", "properties": { "camelCase": { "type": "integer", "format": "int32" }, "new_name": { "type": "integer", "format": "int32" } }, "required": [ "camelCase", "new_name" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json000064400000000000000000000003561046102023000307340ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TupleStruct", "type": "array", "prefixItems": [ { "type": "string" }, { "type": "boolean" } ], "minItems": 2, "maxItems": 2 }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json000064400000000000000000000001521046102023000305540ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UnitStruct", "type": "null" }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.js000064400000000000000000000007371046102023000326140ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "oneOf": [ { "type": "string", "const": "Unit", "x-propertyCount": 0, "x-upperType": "STRING" }, { "type": "object", "properties": { "NewType": true }, "required": [ "NewType" ], "additionalProperties": false, "x-propertyCount": 1, "x-upperType": "OBJECT" } ], "x-propertyCount": 0 }././@LongLink00006440000000000000000000000151000000000000007770Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.000064400000000000000000000005611046102023000326320ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "value": true, "int": { "type": "integer", "format": "int32", "x-propertyCount": 0, "x-upperType": "INTEGER" } }, "required": [ "value", "int" ], "x-upperType": "OBJECT", "x-propertyCount": 2 }././@LongLink00006440000000000000000000000176000000000000007777Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transparent.rs~transparent_newtype_with_validation.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transparent.rs~transparent_new000064400000000000000000000002241046102023000326710ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TransparentNewTypeWithValidation", "type": "string", "minLength": 1 }././@LongLink00006440000000000000000000000166000000000000007776Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transparent.rs~transparent_struct_with_doc.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/transparent.rs~transparent_str000064400000000000000000000002341046102023000327110ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "TransparentStructWithDoc", "description": "A doc comment", "type": "string" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/unset.rs~unset_attributes.json000064400000000000000000000003741046102023000326360ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Struct", "type": "object", "properties": { "field": { "description": "Documentation for field", "type": "string" } }, "required": [ "field" ] }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json000064400000000000000000000001701046102023000274720ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Url", "type": "string", "format": "uri" }schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/uuid.rs~uuid.json000064400000000000000000000001721046102023000300040ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Uuid", "type": "string", "format": "uuid" }././@LongLink00006440000000000000000000000147000000000000007775Lustar schemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.jsonschemars-1.2.1/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.js000064400000000000000000000024061046102023000325300ustar 00000000000000{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "ValidateAttrStruct", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", "minimum": 1.0, "maximum": 100.0 }, "min_max2": { "type": "number", "format": "float", "minimum": 1.0, "maximum": 10.0 }, "regex_str": { "type": "string", "pattern": "^[Hh]ello" }, "contains_str": { "type": "string", "pattern": "substring\\.\\.\\." }, "email_address": { "type": "string", "format": "email" }, "homepage": { "type": "string", "format": "uri" }, "non_empty_str": { "type": "string", "minLength": 1, "maxLength": 100 }, "pair": { "type": "array", "items": { "type": "string" }, "minItems": 2, "maxItems": 2 }, "required_option": { "type": "boolean" }, "x": { "type": "integer", "format": "int32", "minimum": -100, "maximum": 100 } }, "required": [ "min_max", "min_max2", "regex_str", "contains_str", "email_address", "homepage", "non_empty_str", "pair", "required_option", "x" ] }schemars-1.2.1/tests/integration/std_types.rs000064400000000000000000000136101046102023000175040ustar 00000000000000use crate::prelude::*; use std::ffi::{CStr, CString, OsStr, OsString}; use std::marker::PhantomData; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::num::{NonZeroI64, NonZeroU64}; use std::ops::{Bound, Range, RangeInclusive}; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime}; #[test] fn option() { test!(Option) .assert_allows_ser_roundtrip([Some(true), None]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn result() { test!(Result) .assert_allows_ser_roundtrip([Ok(true), Err("oh no!".to_owned())]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn nonzero() { test!(NonZeroI64) .assert_allows_ser_roundtrip([NonZeroI64::MIN, NonZeroI64::MAX]) .assert_rejects_de([Value::from(0)]) .assert_matches_de_roundtrip(arbitrary_values_except( |v| v.as_u64().is_some_and(|u| u > i64::MAX as u64), "FIXME schema allows out-of-range positive integers", )); test!(NonZeroU64) .assert_allows_ser_roundtrip([NonZeroU64::MIN, NonZeroU64::MAX]) .assert_rejects_de([Value::from(0)]) .assert_matches_de_roundtrip(arbitrary_values()); } const IPV4_SAMPLES: [Ipv4Addr; 3] = [ // Commented-out until https://github.com/Stranger6667/jsonschema-rs/issues/512 is fixed // Ipv4Addr::UNSPECIFIED, Ipv4Addr::LOCALHOST, Ipv4Addr::BROADCAST, Ipv4Addr::new(1, 2, 3, 4), ]; const IPV6_SAMPLES: [Ipv6Addr; 4] = [ Ipv6Addr::UNSPECIFIED, Ipv6Addr::LOCALHOST, Ipv4Addr::LOCALHOST.to_ipv6_mapped(), Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), ]; #[test] fn ip_addr() { test!(Ipv4Addr) .assert_allows_ser_roundtrip(IPV4_SAMPLES) .assert_matches_de_roundtrip(arbitrary_values()); test!(Ipv6Addr) .assert_allows_ser_roundtrip(IPV6_SAMPLES) .assert_matches_de_roundtrip(arbitrary_values()); test!(IpAddr) .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(Into::into)) .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(Into::into)) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Custom format 'ip', so arbitrary strings technically allowed by schema", )); } #[test] fn socket_addr() { let port = 12345; test!(SocketAddrV4) .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(|ip| SocketAddrV4::new(ip, port))) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Arbitrary strings allowed by schema", )); test!(SocketAddrV6) .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(|ip| SocketAddrV6::new(ip, port, 0, 0))) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Arbitrary strings allowed by schema", )); test!(SocketAddr) .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(|ip| (ip, port).into())) .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(|ip| (ip, port).into())) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_string, "Arbitrary strings allowed by schema", )); } #[test] fn time() { test!(SystemTime) .assert_allows_ser_roundtrip([SystemTime::UNIX_EPOCH, SystemTime::now()]) .assert_matches_de_roundtrip(arbitrary_values()); test!(Duration) .assert_allows_ser_roundtrip([Duration::from_secs(0), Duration::from_secs_f64(123.456)]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn c_strings() { let strings = [ CString::default(), CString::new("test").unwrap(), CString::new([255]).unwrap(), ]; test!(CString) .assert_allows_ser_roundtrip(strings.clone()) .assert_matches_de_roundtrip(arbitrary_values_except( |v| v.as_str().is_some_and(|s| s.contains('\0')), "CString cannot contain null bytes, but schema does not enforce this", )); test!(Box) .assert_identical::() .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) .assert_matches_de_roundtrip(arbitrary_values_except( |v| v.as_str().is_some_and(|s| s.contains('\0')), "CString cannot contain null bytes, but schema does not enforce this", )); } #[test] fn os_strings() { let strings = [OsString::new(), OsString::from("test")]; test!(OsString) .assert_allows_ser_roundtrip(strings.clone()) .assert_matches_de_roundtrip(arbitrary_values()); test!(Box) .assert_identical::() .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn paths() { let strings = [PathBuf::new(), PathBuf::from("test")]; test!(PathBuf) .assert_identical::() .assert_allows_ser_roundtrip(strings.clone()) .assert_matches_de_roundtrip(arbitrary_values()); test!(Box) .assert_identical::() .assert_identical::() .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn bound() { test!(Bound).assert_allows_ser_roundtrip([ Bound::Included(123), Bound::Excluded(456), Bound::Unbounded, ]); } #[test] fn ranges() { test!(Range) .assert_allows_ser_roundtrip([0..0, 123..456]) .assert_matches_de_roundtrip(arbitrary_values()); test!(RangeInclusive) .assert_allows_ser_roundtrip([0..=0, 123..=456]) .assert_matches_de_roundtrip(arbitrary_values()); } #[test] fn phantom_data() { struct DoesNotImplementJsonSchema; test!(PhantomData) .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/structs.rs000064400000000000000000000074511046102023000172030ustar 00000000000000use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] struct UnitStruct; #[test] fn unit() { test!(UnitStruct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct NormalStruct { foo: String, bar: bool, } #[test] fn normal() { test!(NormalStruct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_allows_de_roundtrip([json!({ "foo": "", "bar": true, "unknown": 123 })]) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct NewType(String); #[test] fn newtype() { test!(NewType) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] struct TupleStruct(String, bool); #[test] fn tuple() { test!(TupleStruct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] struct RenamedFields { camel_case: i32, #[serde(rename = "new_name")] old_name: i32, } #[test] fn renamed_fields() { test!(RenamedFields) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(deny_unknown_fields)] struct DenyUnknownFields { foo: String, bar: bool, } #[test] fn deny_unknown_fields() { test!(DenyUnknownFields) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_rejects_de([json!({ "foo": "", "bar": true, "unknown": 123 })]) .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(example = PropertyOrder::default(), extend("x-custom" = PropertyOrder::default()))] struct PropertyOrder { #[serde(rename = "$defs")] pub defs: UnitStruct, pub examples: UnitStruct, pub properties: UnitStruct, pub required: UnitStruct, #[serde(rename = "$schema")] pub schema: UnitStruct, pub title: UnitStruct, pub r#type: UnitStruct, #[serde(rename = "x-custom")] pub x_custom: UnitStruct, } #[cfg_attr(not(feature = "preserve_order"), ignore)] #[test] fn property_order() { test!(PropertyOrder).assert_snapshot().custom(|schema, _| { fn get_property_keys(value: &Value) -> Vec<&str> { value .as_object() .expect("expected value to be an object") .keys() .map(String::as_str) .collect() } let value = serde_json::to_value(schema).unwrap(); assert!(matches!( get_property_keys(&value).as_slice(), // order of `examples`, `required` and `x-custom` is unspecified &["$schema", "title", "type", "properties", .., "$defs"] )); let field_order = &[ "$defs", "examples", "properties", "required", "$schema", "title", "type", "x-custom", ]; assert_eq!( get_property_keys(&value["properties"]).as_slice(), field_order, ); assert_eq!( get_property_keys(&value["examples"][0]).as_slice(), field_order, ); assert_eq!( get_property_keys(&value["x-custom"]).as_slice(), field_order, ); }); } schemars-1.2.1/tests/integration/test_helper.rs000064400000000000000000000356471046102023000200220ustar 00000000000000use jsonschema::Validator; use pretty_assertions::assert_eq; use schemars::{ generate::{Contract, SchemaSettings}, JsonSchema, Schema, }; use serde::{de::DeserializeOwned, Serialize}; use serde_json::{json, Value}; use snapbox::{data::DataFormat, IntoJson}; use std::{ any::type_name, borrow::Borrow, cell::OnceCell, f64, marker::PhantomData, path::Path, sync::OnceLock, }; pub struct TestHelper { settings: SchemaSettings, name: String, phantom: PhantomData, de_schema: Schema, ser_schema: Schema, de_schema_validator: OnceCell, ser_schema_validator: OnceCell, validator: fn(&T) -> bool, } impl TestHelper { /// Should be used via the `test!(SomeType)` macro pub fn new(name: String, settings: SchemaSettings) -> Self where T: JsonSchema, { let de_schema = schema_for::(&settings, Contract::Deserialize); let ser_schema = schema_for::(&settings, Contract::Serialize); Self { settings, name, phantom: PhantomData, de_schema, ser_schema, de_schema_validator: OnceCell::new(), ser_schema_validator: OnceCell::new(), validator: |_| true, } } /// Should be used via the `test!(value: SomeType)` macro pub fn new_for_value(name: String, settings: SchemaSettings, value: T) -> Self where T: Serialize, { let de_schema = schema_for_value(&settings, Contract::Deserialize, &value); let ser_schema = schema_for_value(&settings, Contract::Serialize, &value); Self { settings, name, phantom: PhantomData, de_schema, ser_schema, de_schema_validator: OnceCell::new(), ser_schema_validator: OnceCell::new(), validator: |_| true, } } pub fn with_validator(&mut self, validator: fn(&T) -> bool) -> &mut Self { self.validator = validator; self } /// Checks the generated schema against the saved schema in the snapshots directory, for manual verification of changes. /// /// Run tests with the SNAPSHOTS env var set to "overwrite" to overwrite any changed snapshots. pub fn assert_snapshot(&self) -> &Self { let common_path = format!("tests/integration/snapshots/{}.json", self.name); let de_path = format!("tests/integration/snapshots/{}.de.json", self.name); let ser_path = format!("tests/integration/snapshots/{}.ser.json", self.name); if self.de_schema == self.ser_schema { snapbox::assert_data_eq!( (&self.de_schema).into_json(), snapbox::Data::read_from(Path::new(&common_path), Some(DataFormat::Json)).raw() ); _ = std::fs::remove_file(de_path); _ = std::fs::remove_file(ser_path); } else { snapbox::assert_data_eq!( (&self.de_schema).into_json(), snapbox::Data::read_from(Path::new(&de_path), Some(DataFormat::Json)).raw() ); snapbox::assert_data_eq!( (&self.ser_schema).into_json(), snapbox::Data::read_from(Path::new(&ser_path), Some(DataFormat::Json)).raw() ); _ = std::fs::remove_file(common_path); } self } /// Checks that the schema generated for this type is identical to that of another type. pub fn assert_identical(&self) -> &Self where T: JsonSchema, { snapbox::assert_data_eq!( (&self.de_schema).into_json(), schema_for::(&self.settings, Contract::Deserialize) .into_json() .raw() ); snapbox::assert_data_eq!( (&self.ser_schema).into_json(), schema_for::(&self.settings, Contract::Serialize) .into_json() .raw() ); let t = type_name::(); let t2 = type_name::(); assert_eq!( T::schema_name(), T2::schema_name(), "`{t}` and `{t2}` have identical schemas, so should have the same schema_name" ); assert_eq!( T::schema_id(), T2::schema_id(), "`{t}` and `{t2}` have identical schemas, so should have the same schema_id" ); assert_eq!( T::inline_schema(), T2::inline_schema(), "`{t}` and `{t2}` have identical schemas, so should have the same inline_schema" ); self } pub fn custom(&self, assertion: impl Fn(&Schema, Contract)) -> &Self { assertion(&self.de_schema, Contract::Deserialize); assertion(&self.ser_schema, Contract::Serialize); self } fn de_schema_validate(&self, instance: &Value) -> bool { self.de_schema_validator .get_or_init(|| build_validator(&self.de_schema)) .is_valid(instance) } fn ser_schema_validate(&self, instance: &Value) -> bool { self.ser_schema_validator .get_or_init(|| build_validator(&self.ser_schema)) .is_valid(instance) } } fn build_validator(schema: &Schema) -> Validator { jsonschema::options() .should_validate_formats(true) .build(schema.as_value()) .expect("valid schema") } impl TestHelper { /// Checks that the "serialize" schema allows the given sample values when serialized to JSON. /// If `T implements `DeserializeOwned`, prefer using `assert_allows_ser_roundtrip()` pub fn assert_allows_ser_only(&self, samples: impl IntoIterator) -> &Self { for sample in samples { let json = serde_json::to_value(&sample).unwrap(); assert!( (self.validator)(&sample), "invalid test case - attempt to serialize value failing validation: {json}" ); assert!( self.ser_schema_validate(&json), "serialize schema should allow serialized value: {json}" ); } self } } impl TestHelper { /// Checks that the "serialize" schema allows the given sample values when serialized to JSON /// and, if the value can then be deserialized, that the "deserialize" schema also allows it. pub fn assert_allows_ser_roundtrip(&self, samples: impl IntoIterator) -> &Self { for sample in samples { let json = serde_json::to_value(&sample).unwrap(); assert!( (self.validator)(&sample), "invalid test case - attempt to serialize value failing validation: {json}" ); assert!( self.ser_schema_validate(&json), "serialize schema should allow serialized value: {json}" ); if T::deserialize(&json).is_ok() { assert!( (self.validator)(&sample), "invalid test case - roundtripped value fails validation: {json}" ); assert!( self.de_schema_validate(&json), "deserialize schema should allow value accepted by deserialization: {json}" ); } else { assert!( !self.de_schema_validate(&json), "deserialize schema should reject undeserializable value: {json}" ); } } self } /// Checks that the "deserialize" schema allow the given sample values, and the "serialize" /// schema allows the value obtained from deserializing then re-serializing the sample values /// (only for values that can successfully be serialized). /// /// This is intended for types that have different serialize/deserialize schemas, or when you /// want to test specific values that are valid for deserialization but not for serialization. pub fn assert_allows_de_roundtrip( &self, samples: impl IntoIterator>, ) -> &Self { for sample in samples { let sample = sample.borrow(); let Ok(deserialized) = T::deserialize(sample) else { panic!( "expected deserialize to succeed for {}: {sample}", type_name::() ) }; assert!( (self.validator)(&deserialized), "invalid test case - deserialized value fails validation: {sample}" ); assert!( self.de_schema_validate(sample), "deserialize schema should allow value accepted by deserialization: {sample}" ); if let Ok(serialized) = serde_json::to_value(&deserialized) { assert!( self.ser_schema_validate(&serialized), "serialize schema should allow serialized value: {serialized}" ); } } self } /// Checks that the "deserialize" schema allows only the given sample values that successfully /// deserialize and pass validation. /// /// This is intended to be given a range of values (see `arbitrary_values`), allowing limited /// fuzzing. pub fn assert_matches_de_roundtrip( &self, samples: impl IntoIterator>, ) -> &Self { for value in samples { let value = value.borrow(); match T::deserialize(value) { Ok(deserialized) if (self.validator)(&deserialized) => { assert!( self.de_schema_validate(value), "deserialize schema should allow value accepted by deserialization: {value}" ); if let Ok(serialized) = serde_json::to_value(&deserialized) { assert!( self.ser_schema_validate(&serialized), "serialize schema should allow serialized value: {serialized}" ); } } _ => { assert!( !self.de_schema_validate(value), "deserialize schema should reject invalid value: {value}" ); // This assertion isn't necessarily valid in the general case but it would be // odd (though not necessarily wrong) for it to fail. If this does ever fail // a case that should be legitimate, then this assert can be removed/weakened. assert!( !self.ser_schema_validate(value), "serialize schema should reject invalid value: {value}" ); } } } self } /// Checks that the "deserialize" schema does not allow any of the given sample values. /// /// While `assert_matches_de_roundtrip()` would also work in this case, `assert_rejects_de()` /// has the advantage that it also verifies that the test case itself is actually covering the /// failure case as intended. pub fn assert_rejects_de(&self, values: impl IntoIterator>) -> &Self { for value in values { let value = value.borrow(); assert!( T::deserialize(value).is_err(), "invalid test case - expected deserialize to fail for {}: {value}", type_name::() ); assert!( !self.de_schema_validate(value), "deserialize schema should reject invalid value: {value}" ); } self } /// Checks that neither "serialize" nor "deserialize" schemas allow any of the given sample /// values when serialized to JSON due to the values failing validation. pub fn assert_rejects_invalid(&self, samples: impl IntoIterator) -> &Self { for sample in samples { let json = serde_json::to_value(&sample).unwrap(); assert!( !(self.validator)(&sample), "invalid test case - serialized value passes validation: {json}" ); assert!( !self.de_schema_validate(&json), "deserialize schema should reject invalid value: {json}" ); assert!( !self.ser_schema_validate(&json), "serialize schema should reject invalid value: {json}" ); } self } /// Checks that both the "serialize" and "deserialize" schema allow the type's default value /// when serialized to JSON. pub fn assert_allows_ser_roundtrip_default(&self) -> &Self where T: Default, { self.assert_allows_ser_roundtrip([T::default()]) } } fn schema_for(base_settings: &SchemaSettings, contract: Contract) -> Schema { base_settings .clone() .with(|s| s.contract = contract) .into_generator() .into_root_schema_for::() } fn schema_for_value( base_settings: &SchemaSettings, contract: Contract, value: impl Serialize, ) -> Schema { base_settings .clone() .with(|s| s.contract = contract) .into_generator() .into_root_schema_for_value(&value) .unwrap() } /// Returns an iterator over an selection of arbitrary JSON values. /// /// This is intended to be used as `test!(...).assert_matches_de_roundtrip(arbitrary_values())` pub fn arbitrary_values() -> impl Iterator { fn primitives() -> impl Iterator { [ Value::Null, false.into(), true.into(), 0.into(), 255.into(), (-1).into(), u64::MAX.into(), f64::consts::PI.into(), "".into(), "0".into(), "3E8".into(), "\tPâté costs “£1”\0".into(), Value::Array(Default::default()), Value::Object(Default::default()), ] .into_iter() } // TODO once MSRV has reached 1.80, replace this with LazyLock static VALUES: OnceLock> = OnceLock::new(); VALUES .get_or_init(|| { Vec::from_iter( primitives() .chain(primitives().map(|p| json!([p]))) .chain(primitives().map(|p| json!({"key": p}))), ) }) .iter() } /// Returns an iterator over an selection of arbitrary JSON values, except for value that match /// the given filter predicate. /// /// This is to handle known cases of schemas not matching the actual deserialize behaviour. pub fn arbitrary_values_except( filter: impl Fn(&Value) -> bool, _reason: &str, ) -> impl Iterator { arbitrary_values().filter(move |v| !filter(v)) } schemars-1.2.1/tests/integration/transform.rs000064400000000000000000000035651046102023000175110ustar 00000000000000use crate::prelude::*; use pretty_assertions::assert_eq; use schemars::{ transform::{RecursiveTransform, Transform}, Schema, }; use serde_json::Map; fn insert_upper_type(schema: &mut Schema) { if let Some(Value::String(ty)) = schema.get("type") { schema.insert("x-upperType".to_owned(), ty.to_uppercase().into()); } } fn insert_property_count(schema: &mut Schema) { let count = schema .get("properties") .and_then(Value::as_object) .map_or(0, Map::len); schema.insert("x-propertyCount".to_owned(), count.into()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(transform = RecursiveTransform(insert_upper_type), transform = insert_property_count)] struct Struct { value: Value, #[schemars(transform = insert_property_count)] int: i32, } #[test] fn transform_struct() { test!(Struct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .custom(assert_upper_type_valid); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[schemars(transform = RecursiveTransform(insert_upper_type), transform = insert_property_count)] enum External { #[default] #[schemars(transform = insert_property_count)] Unit, #[schemars(transform = insert_property_count)] NewType(Value), } #[test] fn transform_enum() { test!(External) .assert_snapshot() .assert_allows_ser_roundtrip_default() .custom(assert_upper_type_valid); } fn assert_upper_type_valid(schema: &Schema, _: schemars::generate::Contract) { let mut schema = schema.clone(); RecursiveTransform(|s: &mut Schema| { assert_eq!( s.remove("x-upperType").map(|v| v.to_string()), s.get("type").map(|v| v.to_string().to_uppercase()), ); }) .transform(&mut schema); assert!(!schema.to_value().to_string().contains("x-upperType")); } schemars-1.2.1/tests/integration/transparent.rs000064400000000000000000000030371046102023000200310ustar 00000000000000use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(transparent)] pub struct TransparentStruct { inner: String, } #[test] fn transparent_struct() { test!(TransparentStruct) .assert_identical::() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(transparent)] /// A doc comment pub struct TransparentStructWithDoc { /// Another doc comment (ignored) inner: String, } #[test] fn transparent_struct_with_doc() { test!(TransparentStructWithDoc) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(transparent)] pub struct TransparentNewType(String); #[test] fn transparent_newtype() { test!(TransparentNewType) .assert_identical::() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values()); } #[derive(JsonSchema, Deserialize, Serialize)] #[serde(transparent)] pub struct TransparentNewTypeWithValidation(#[schemars(length(min = 1))] String); #[test] fn transparent_newtype_with_validation() { test!(TransparentNewTypeWithValidation) .with_validator(|v| !v.0.is_empty()) .assert_snapshot() .assert_allows_ser_roundtrip([TransparentNewTypeWithValidation("a@a.com".into())]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/unset.rs000064400000000000000000000017221046102023000166250ustar 00000000000000use crate::prelude::*; #[derive(Default, Deserialize, Serialize, JsonSchema)] #[serde(from = "FlatStruct", rename_all = "kebab-case")] #[schemars(!from)] pub struct Struct { #[serde(flatten)] inner: Inner, } #[derive(Default, Deserialize, Serialize, JsonSchema)] pub struct Inner { /// Documentation for field pub field: String, } #[derive(Deserialize)] pub struct FlatStruct { pub field: String, } impl From for Struct { fn from(value: FlatStruct) -> Self { Self { inner: Inner { field: value.field }, } } } #[test] fn unset_attributes() { test!(Struct) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); } schemars-1.2.1/tests/integration/url.rs000064400000000000000000000005211046102023000162650ustar 00000000000000use crate::prelude::*; use url2::Url; #[test] fn url() { test!(Url) .assert_snapshot() .assert_allows_ser_roundtrip( ["http://example.com", "data:text/plain,test"] .iter() .map(|s| s.parse().unwrap()), ) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/uuid.rs000064400000000000000000000004021046102023000164270ustar 00000000000000use crate::prelude::*; use uuid1::Uuid; #[test] fn uuid() { test!(Uuid) .assert_snapshot() .assert_allows_ser_roundtrip([Uuid::nil(), Uuid::max(), Uuid::from_u128(1234567890)]) .assert_matches_de_roundtrip(arbitrary_values()); } schemars-1.2.1/tests/integration/validator.rs000064400000000000000000000100501046102023000174460ustar 00000000000000use crate::prelude::*; use regex::Regex; use validator::Validate; const ONE: f32 = 1.0; const HUNDRED: f32 = 10.0; // In real code, this would use something like a LazyLock fn hello_regex() -> Regex { Regex::new(r"^[Hh]ello").unwrap() } #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct ValidateAttrStruct { #[validate(range(min = 1.0, max = 100.0))] min_max: f32, #[validate(range(min = ONE, max = HUNDRED))] min_max2: f32, #[validate(regex(path = hello_regex()))] regex_str: String, #[validate(contains(pattern = "substring..."))] contains_str: String, #[validate(email)] email_address: String, #[validate(url)] homepage: String, #[validate(length(min = 1, max = 100))] non_empty_str: String, #[validate(length(equal = 2))] pair: Vec, #[validate(required)] required_option: Option, #[validate(required, nested)] #[serde(flatten)] required_flattened: Option, } #[derive(JsonSchema, Deserialize, Serialize, Validate)] pub struct ValidateAttrInner { #[validate(range(min = -100, max = 100))] x: i32, } impl Default for ValidateAttrStruct { fn default() -> Self { Self { min_max: 1.0, min_max2: 1.0, regex_str: "Hello world".to_owned(), contains_str: "Contains substring...".to_owned(), email_address: "test@test.test".to_owned(), homepage: "http://test.test".to_owned(), non_empty_str: "test".to_owned(), pair: vec!["a".to_owned(), "b".to_owned()], required_option: Some(true), required_flattened: Some(ValidateAttrInner { x: 0 }), } } } impl ValidateAttrStruct { pub fn invalid_values() -> impl IntoIterator { static MUTATORS: &[fn(&mut ValidateAttrStruct)] = &[ |v| v.min_max = 0.9, |v| v.min_max = 100.1, |v| v.min_max2 = 0.9, |v| v.min_max2 = 100.1, |v| v.regex_str = "fail".to_owned(), |v| v.contains_str = "fail".to_owned(), |v| v.email_address = "fail".to_owned(), |v| v.homepage = "fail".to_owned(), |v| v.non_empty_str = String::new(), |v| v.pair = Vec::new(), |v| v.pair = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()], |v| v.required_option = None, |v| v.required_flattened = None, |v| v.required_flattened = Some(ValidateAttrInner { x: -101 }), |v| v.required_flattened = Some(ValidateAttrInner { x: 101 }), ]; MUTATORS.iter().map(|f| { let mut result = ValidateAttrStruct::default(); f(&mut result); result }) } } #[test] fn validate_attrs() { test!(ValidateAttrStruct) .with_validator(|v| v.validate().is_ok()) .assert_snapshot() .assert_allows_ser_roundtrip_default() .assert_rejects_invalid(ValidateAttrStruct::invalid_values()) .assert_matches_de_roundtrip(arbitrary_values()); } #[allow(dead_code)] #[derive(JsonSchema)] #[schemars(rename = "ValidateAttrStruct")] pub struct SchemarsAttrStruct { #[schemars(range(min = 1.0, max = 100.0))] min_max: f32, #[schemars(range(min = ONE, max = HUNDRED))] min_max2: f32, #[schemars(regex(pattern = hello_regex()))] regex_str: String, #[schemars(contains(pattern = "substring..."))] contains_str: String, #[schemars(email)] email_address: String, #[schemars(url)] homepage: String, #[schemars(length(min = 1, max = 100))] non_empty_str: String, #[schemars(length(equal = 2))] pair: Vec, #[schemars(required)] required_option: Option, #[schemars(required)] #[serde(flatten)] required_flattened: Option, } #[allow(dead_code)] #[derive(JsonSchema)] pub struct SchemarsAttrInner { #[schemars(range(min = -100, max = 100))] x: i32, } #[test] fn schemars_attrs() { test!(SchemarsAttrStruct).assert_identical::(); } schemars-1.2.1/tests/no_std.rs000064400000000000000000000007031046102023000144300ustar 00000000000000#![no_std] use schemars::{schema_for, JsonSchema}; #[derive(JsonSchema, Default)] pub struct MyStruct { /// A number pub my_int: i32, #[schemars(extend("x-test" = {"k": "v"}))] pub my_bool: bool, pub my_nullable_enum: Option, } #[derive(JsonSchema)] pub enum MyEnum { StringNewType(&'static str), StructVariant { floats: &'static [f32] }, } #[test] fn test_no_std() { let _schema = schema_for!(MyStruct); } schemars-1.2.1/tests/ui/example_fn.rs000064400000000000000000000002001046102023000156650ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[schemars(example = "my_fn")] pub struct Struct; fn my_fn() {} fn main() {} schemars-1.2.1/tests/ui/example_fn.stderr000064400000000000000000000007671046102023000165660ustar 00000000000000error: `example` value must be an expression, and string literals that may be interpreted as function paths are currently disallowed to avoid migration errors (this restriction may be relaxed in a future version of schemars). If you want to use the result of a function, use `#[schemars(example = my_fn())]`. Or to use the string literal value, use `#[schemars(example = &"my_fn")]`. --> tests/ui/example_fn.rs:4:22 | 4 | #[schemars(example = "my_fn")] | ^^^^^^^ schemars-1.2.1/tests/ui/invalid_attrs.rs000064400000000000000000000011741046102023000164250ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[serde( default = 0, foo, deny_unknown_fields, deny_unknown_fields, inline = 1, inline, inline, with = "String", serialize_with = "String", a::path )] pub struct Struct1 { #[serde(serialize_with = "u64")] pub field: u32, } #[derive(JsonSchema)] #[schemars( default = 0, foo, deny_unknown_fields, deny_unknown_fields, inline = 1, inline, inline, with = "String", serialize_with = "String", a::path )] pub struct Struct2 { #[schemars(serialize_with = "u64")] pub field: u32, } fn main() {} schemars-1.2.1/tests/ui/invalid_attrs.stderr000064400000000000000000000030611046102023000173010ustar 00000000000000error: expected serde default attribute to be a string: `default = "..."` --> tests/ui/invalid_attrs.rs:5:15 | 5 | default = 0, | ^ error: duplicate serde attribute `deny_unknown_fields` --> tests/ui/invalid_attrs.rs:8:5 | 8 | deny_unknown_fields, | ^^^^^^^^^^^^^^^^^^^ error: unknown serde container attribute `with` --> tests/ui/invalid_attrs.rs:12:5 | 12 | with = "String", | ^^^^ error: expected serde default attribute to be a string: `default = "..."` --> tests/ui/invalid_attrs.rs:23:15 | 23 | default = 0, | ^ error: duplicate serde attribute `deny_unknown_fields` --> tests/ui/invalid_attrs.rs:26:5 | 26 | deny_unknown_fields, | ^^^^^^^^^^^^^^^^^^^ error: unknown schemars attribute `serialize_with` --> tests/ui/invalid_attrs.rs:35:16 | 35 | #[schemars(serialize_with = "u64")] | ^^^^^^^^^^^^^^ error: unexpected value of schemars inline attribute item --> tests/ui/invalid_attrs.rs:27:12 | 27 | inline = 1, | ^^^ error: duplicate schemars attribute item `inline` --> tests/ui/invalid_attrs.rs:29:5 | 29 | inline, | ^^^^^^ error: unknown schemars attribute `foo` --> tests/ui/invalid_attrs.rs:24:5 | 24 | foo, | ^^^ error: unknown schemars attribute `serialize_with` --> tests/ui/invalid_attrs.rs:31:5 | 31 | serialize_with = "String", | ^^^^^^^^^^^^^^ error: unknown schemars attribute `a::path` --> tests/ui/invalid_attrs.rs:32:5 | 32 | a::path | ^^^^^^^ schemars-1.2.1/tests/ui/invalid_extend.rs000064400000000000000000000004321046102023000165530ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[schemars(extend(x))] #[schemars(extend("x"))] #[schemars(extend("x" = ))] #[schemars(extend("y" = "ok!", "y" = "duplicated!"), extend("y" = "duplicated!"))] #[schemars(extend("y" = "duplicated!"))] pub struct Struct; fn main() {} schemars-1.2.1/tests/ui/invalid_extend.stderr000064400000000000000000000017001046102023000174310ustar 00000000000000error: expected string literal --> tests/ui/invalid_extend.rs:4:19 | 4 | #[schemars(extend(x))] | ^ error: expected `=` --> tests/ui/invalid_extend.rs:5:22 | 5 | #[schemars(extend("x"))] | ^ error: Expected extension value --> tests/ui/invalid_extend.rs:6:25 | 6 | #[schemars(extend("x" = ))] | ^ error: Duplicate extension key 'y' --> tests/ui/invalid_extend.rs:7:32 | 7 | #[schemars(extend("y" = "ok!", "y" = "duplicated!"), extend("y" = "duplicated!"))] | ^^^ error: Duplicate extension key 'y' --> tests/ui/invalid_extend.rs:7:61 | 7 | #[schemars(extend("y" = "ok!", "y" = "duplicated!"), extend("y" = "duplicated!"))] | ^^^ error: Duplicate extension key 'y' --> tests/ui/invalid_extend.rs:8:19 | 8 | #[schemars(extend("y" = "duplicated!"))] | ^^^ schemars-1.2.1/tests/ui/invalid_rename.rs000064400000000000000000000002711046102023000165340ustar 00000000000000use schemars::JsonSchema; struct DoesNotImplJsonSchema; #[derive(JsonSchema)] #[schemars(rename = "} } {T} {U} {T::test} } {T")] pub struct Struct1 { pub t: T, } fn main() {} schemars-1.2.1/tests/ui/invalid_rename.stderr000064400000000000000000000015401046102023000174130ustar 00000000000000error: invalid name format string: unmatched `}` found --> tests/ui/invalid_rename.rs:6:21 | 6 | #[schemars(rename = "} } {T} {U} {T::test} } {T")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid name format string: expected generic param, found `U` --> tests/ui/invalid_rename.rs:6:21 | 6 | #[schemars(rename = "} } {T} {U} {T::test} } {T")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid name format string: expected generic param, found `T::test` --> tests/ui/invalid_rename.rs:6:21 | 6 | #[schemars(rename = "} } {T} {U} {T::test} } {T")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid name format string: found `{` without matching `}` --> tests/ui/invalid_rename.rs:6:21 | 6 | #[schemars(rename = "} } {T} {U} {T::test} } {T")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ schemars-1.2.1/tests/ui/invalid_unset_attrs.rs000064400000000000000000000003261046102023000176410ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[serde(deny_unknown_fields, default)] #[schemars(!unknown, deny_unknown_fields, !deny_unknown_fields, !default, !default, !from)] pub struct Struct1; fn main() {} schemars-1.2.1/tests/ui/invalid_unset_attrs.stderr000064400000000000000000000021661046102023000205240ustar 00000000000000error: duplicate schemars attribute item `!default` --> tests/ui/invalid_unset_attrs.rs:5:75 | 5 | #[schemars(!unknown, deny_unknown_fields, !deny_unknown_fields, !default, !default, !from)] | ^^^^^^^^ error: schemars attribute cannot contain both `deny_unknown_fields` and `!deny_unknown_fields` --> tests/ui/invalid_unset_attrs.rs:5:43 | 5 | #[schemars(!unknown, deny_unknown_fields, !deny_unknown_fields, !default, !default, !from)] | ^^^^^^^^^^^^^^^^^^^^ error: useless `!from` - no serde attribute containing `from` is present --> tests/ui/invalid_unset_attrs.rs:5:85 | 5 | #[schemars(!unknown, deny_unknown_fields, !deny_unknown_fields, !default, !default, !from)] | ^^^^^ error: useless `!unknown` - no serde attribute containing `unknown` is present --> tests/ui/invalid_unset_attrs.rs:5:12 | 5 | #[schemars(!unknown, deny_unknown_fields, !deny_unknown_fields, !default, !default, !from)] | ^^^^^^^^ schemars-1.2.1/tests/ui/invalid_validation_attrs.rs000064400000000000000000000015251046102023000206370ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[validate(email)] pub struct Struct1(#[validate(regex, foo, length(min = 1, equal = 2, bar))] String); #[derive(JsonSchema)] #[schemars(email)] pub struct Struct2(#[schemars(regex, foo, length(min = 1, equal = 2, bar))] String); #[derive(JsonSchema)] pub struct Struct3( #[validate( regex = "foo", contains = "bar", regex(pattern = "baz"), regex(path = "baz"), phone, email, url )] String, ); #[derive(JsonSchema)] pub struct Struct4( #[schemars( regex = "foo", contains = "bar", regex(path = "baz"), regex(pattern = "baz"), phone, email(code = "code_str", message = "message"), email = "foo", email, email, url )] String, ); fn main() {} schemars-1.2.1/tests/ui/invalid_validation_attrs.stderr000064400000000000000000000075171046102023000215250ustar 00000000000000error: expected validate regex attribute item to be of the form `regex(...)` --> tests/ui/invalid_validation_attrs.rs:5:31 | 5 | pub struct Struct1(#[validate(regex, foo, length(min = 1, equal = 2, bar))] String); | ^^^^^ error: expected schemars regex attribute item to be of the form `regex(...)` --> tests/ui/invalid_validation_attrs.rs:9:31 | 9 | pub struct Struct2(#[schemars(regex, foo, length(min = 1, equal = 2, bar))] String); | ^^^^^ error: schemars attribute cannot contain both `equal` and `min` --> tests/ui/invalid_validation_attrs.rs:9:59 | 9 | pub struct Struct2(#[schemars(regex, foo, length(min = 1, equal = 2, bar))] String); | ^^^^^^^^^ error: unknown item in schemars length attribute: `bar` --> tests/ui/invalid_validation_attrs.rs:9:70 | 9 | pub struct Struct2(#[schemars(regex, foo, length(min = 1, equal = 2, bar))] String); | ^^^ error: unknown schemars attribute `foo` --> tests/ui/invalid_validation_attrs.rs:9:38 | 9 | pub struct Struct2(#[schemars(regex, foo, length(min = 1, equal = 2, bar))] String); | ^^^ error: unknown schemars attribute `email` --> tests/ui/invalid_validation_attrs.rs:8:12 | 8 | #[schemars(email)] | ^^^^^ error: expected validate regex attribute item to be of the form `regex(...)` --> tests/ui/invalid_validation_attrs.rs:14:9 | 14 | regex = "foo", | ^^^^^^^^^^^^^ error: expected validate contains attribute item to be of the form `contains(...)` --> tests/ui/invalid_validation_attrs.rs:15:9 | 15 | contains = "bar", | ^^^^^^^^^^^^^^^^ error: `pattern` is not supported in `validate(regex(...))` attribute - use either `validate(regex(path = ...))` or `schemars(regex(pattern = ...))` instead --> tests/ui/invalid_validation_attrs.rs:16:15 | 16 | regex(pattern = "baz"), | ^^^^^^^^^^^^^^^ error: `validate(regex(...))` attribute requires `path = ...` --> tests/ui/invalid_validation_attrs.rs:16:9 | 16 | regex(pattern = "baz"), | ^^^^^^^^^^^^^^^^^^^^^^ error: expected schemars regex attribute item to be of the form `regex(...)` --> tests/ui/invalid_validation_attrs.rs:28:9 | 28 | regex = "foo", | ^^^^^^^^^^^^^ error: expected schemars contains attribute item to be of the form `contains(...)` --> tests/ui/invalid_validation_attrs.rs:29:9 | 29 | contains = "bar", | ^^^^^^^^^^^^^^^^ error: `path` is not supported in `schemars(regex(...))` attribute - use `schemars(regex(pattern = ...))` instead --> tests/ui/invalid_validation_attrs.rs:30:15 | 30 | regex(path = "baz"), | ^^^^^^^^^^^^ error: `schemars(regex(...))` attribute requires `pattern = ...` --> tests/ui/invalid_validation_attrs.rs:30:9 | 30 | regex(path = "baz"), | ^^^^^^^^^^^^^^^^^^^ error: unexpected value of schemars email attribute item --> tests/ui/invalid_validation_attrs.rs:33:14 | 33 | email(code = "code_str", message = "message"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unexpected value of schemars email attribute item --> tests/ui/invalid_validation_attrs.rs:34:15 | 34 | email = "foo", | ^^^^^^^ error: duplicate schemars attribute item `email` --> tests/ui/invalid_validation_attrs.rs:36:9 | 36 | email, | ^^^^^ error: schemars attribute cannot contain both `url` and `email` --> tests/ui/invalid_validation_attrs.rs:37:9 | 37 | url | ^^^ error: unknown schemars attribute `phone` --> tests/ui/invalid_validation_attrs.rs:32:9 | 32 | phone, | ^^^^^ schemars-1.2.1/tests/ui/repr_missing.rs000064400000000000000000000001451046102023000162600ustar 00000000000000use schemars::JsonSchema_repr; #[derive(JsonSchema_repr)] pub enum Enum { Unit, } fn main() {} schemars-1.2.1/tests/ui/repr_missing.stderr000064400000000000000000000004371046102023000171430ustar 00000000000000error: JsonSchema_repr: missing #[repr(...)] attribute --> $DIR/repr_missing.rs:3:10 | 3 | #[derive(JsonSchema_repr)] | ^^^^^^^^^^^^^^^ | = note: this error originates in the derive macro `JsonSchema_repr` (in Nightly builds, run with -Z macro-backtrace for more info) schemars-1.2.1/tests/ui/repr_non_unit_variant.rs000064400000000000000000000002031046102023000201570ustar 00000000000000use schemars::JsonSchema_repr; #[derive(JsonSchema_repr)] #[repr(u8)] pub enum Enum { Unit, EmptyTuple(), } fn main() {} schemars-1.2.1/tests/ui/repr_non_unit_variant.stderr000064400000000000000000000002051046102023000210400ustar 00000000000000error: JsonSchema_repr: must be a unit variant --> $DIR/repr_non_unit_variant.rs:7:5 | 7 | EmptyTuple(), | ^^^^^^^^^^^^ schemars-1.2.1/tests/ui/schema_for_arg_value.rs000064400000000000000000000001151046102023000177070ustar 00000000000000use schemars::schema_for; fn main() { let _schema = schema_for!(123); } schemars-1.2.1/tests/ui/schema_for_arg_value.stderr000064400000000000000000000005361046102023000205750ustar 00000000000000error: This argument to `schema_for!` is not a type - did you mean to use `schema_for_value!` instead? --> $DIR/schema_for_arg_value.rs:4:19 | 4 | let _schema = schema_for!(123); | ^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `schema_for` (in Nightly builds, run with -Z macro-backtrace for more info) schemars-1.2.1/tests/ui/transform_str.rs000064400000000000000000000001571046102023000164650ustar 00000000000000use schemars::JsonSchema; #[derive(JsonSchema)] #[schemars(transform = "x")] pub struct Struct; fn main() {} schemars-1.2.1/tests/ui/transform_str.stderr000064400000000000000000000004121046102023000173360ustar 00000000000000error: Expected a `fn(&mut Schema)` or other value implementing `schemars::transform::Transform`, found `&str`. Did you mean `#[schemars(transform = x)]`? --> tests/ui/transform_str.rs:4:24 | 4 | #[schemars(transform = "x")] | ^^^ schemars-1.2.1/tests/ui.rs000064400000000000000000000001411046102023000135530ustar 00000000000000#[test] fn ui() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); }