mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 21:48:02 +00:00
Compare commits
493 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 415d9fc560 | |||
| 7c58427e12 | |||
| 9d3410e3f4 | |||
| 2fb6748bf1 | |||
| f8137c79a2 | |||
| b7dbf7e3cb | |||
| 7c836915fc | |||
| aa2d9b208a | |||
| 3a7c11c82c | |||
| 11ce4402bd | |||
| 8047570160 | |||
| b395215875 | |||
| a437ff6bf7 | |||
| 20fc31c78a | |||
| ad2b064b0a | |||
| dec153b8fa | |||
| e219a0d4b7 | |||
| c78f7d2e30 | |||
| 502a065a4c | |||
| 027112eccb | |||
| 8c3445efe4 | |||
| 88b6a9abf4 | |||
| fa298c9df4 | |||
| c4a07ed4e8 | |||
| c4986f10b9 | |||
| 2d607de146 | |||
| 19956e6b8e | |||
| ec13eb4ed6 | |||
| ae00c4acb7 | |||
| 85d0b9ccd8 | |||
| e60f62a289 | |||
| e04f0ba2de | |||
| c8184be238 | |||
| 896d91f0bb | |||
| 915686d0ec | |||
| 3a682c951b | |||
| ca79f61d0f | |||
| ddb7c4b30f | |||
| 4855fb467f | |||
| 6dffc0b1c8 | |||
| 15be2a600a | |||
| 1799547846 | |||
| 2dbeefb11b | |||
| 8a3c29ff19 | |||
| defc24d361 | |||
| 2316610760 | |||
| c09e2bd690 | |||
| fe7dcc4cd8 | |||
| a20e66e131 | |||
| 1c1a5d95cd | |||
| ee3c2372fb | |||
| bfb020d975 | |||
| 6805bba308 | |||
| 2659b94a62 | |||
| c451415d9f | |||
| 553a9ff15f | |||
| 6f5eb7d207 | |||
| 55615e8f8e | |||
| 1d7899d671 | |||
| 97168d3a24 | |||
| 373b11dda7 | |||
| 69072f2423 | |||
| 5b37e8a531 | |||
| b47f4dfa96 | |||
| cbe98a9888 | |||
| 957996f5fb | |||
| 169988206a | |||
| 840f6ec9b8 | |||
| bf9ebea392 | |||
| 6c316d7cb5 | |||
| a4ac0c2bc6 | |||
| ed76364f87 | |||
| 57e21a1afa | |||
| bb58726133 | |||
| 3f6925125b | |||
| fd4decf2fe | |||
| 00b1b6b2b5 | |||
| cf141aa8c7 | |||
| ff3aee490a | |||
| 10bcfc0047 | |||
| 2f03899197 | |||
| 3bea3b6989 | |||
| 85bf29c446 | |||
| 900c922f41 | |||
| 9cf3f2ed7d | |||
| 1ffbeb9516 | |||
| 1051c5e6b7 | |||
| be255d62c8 | |||
| 263a1dbdd7 | |||
| 23dea60e1a | |||
| 690785f129 | |||
| 69aa109fd3 | |||
| 6bea2e04e4 | |||
| a1a82c3c55 | |||
| 7987ad700e | |||
| 0990d97a77 | |||
| a9150aad74 | |||
| 5ac3d84d99 | |||
| f916ec6baa | |||
| 7f831225a9 | |||
| a16893429b | |||
| 260511d149 | |||
| 7659fb686d | |||
| f669f16127 | |||
| 93f43cedaa | |||
| b6c7ce8ec3 | |||
| 35c963101b | |||
| 8909fc0c60 | |||
| 3c747e4585 | |||
| 1b89ff50a9 | |||
| c069b5c640 | |||
| 79f3484ab8 | |||
| ac8b7ea052 | |||
| c1b2f43917 | |||
| 51f8b0c52d | |||
| 6c4cae6b09 | |||
| 4da055a286 | |||
| 66c5d2b153 | |||
| 4bddf1b953 | |||
| 908f32175a | |||
| 3e1cf11060 | |||
| 723fcacad7 | |||
| 94acfe19e6 | |||
| b4677fde9d | |||
| c85e4240be | |||
| 363deb84cc | |||
| 106da4905f | |||
| f9baf39dc3 | |||
| 3deb08946e | |||
| 43f5eb5c69 | |||
| 5fcfbed3ea | |||
| f3869307cc | |||
| babafa54d2 | |||
| ad6c548573 | |||
| 80b2f5f9e1 | |||
| 2130ba5788 | |||
| a1ddb18c92 | |||
| ae38b27aee | |||
| da3998acfb | |||
| b9de3658ad | |||
| 16af2d9ce7 | |||
| b426ff81e3 | |||
| b0e87aeecd | |||
| a685dcf680 | |||
| 88da17ca21 | |||
| d91f8ba950 | |||
| aa5aa611d4 | |||
| da0b473d60 | |||
| 49d098debd | |||
| 40f1d19dbe | |||
| 514848b584 | |||
| 168b6cf789 | |||
| 8b0e95b6de | |||
| e3a4165363 | |||
| 6ac8049b92 | |||
| 13a33b3c33 | |||
| a8bdd17333 | |||
| 1c9601358b | |||
| f0d1ae08f3 | |||
| e3eaa6a3dd | |||
| 6a630cf283 | |||
| 7bfd518dd4 | |||
| 723a9491e2 | |||
| 2b44efb085 | |||
| 03dc0fc137 | |||
| 85cb0c478e | |||
| abe7194480 | |||
| aaccac7413 | |||
| 7cd4d84cac | |||
| 04ff3e8f95 | |||
| dc3031b614 | |||
| 1e2f931d0c | |||
| 930401b0dd | |||
| cb6eaea151 | |||
| b6f339ca36 | |||
| 2a5caea1a8 | |||
| b9f93f99aa | |||
| eb5cd476ba | |||
| 8478a3b7dd | |||
| dbb909136e | |||
| ad8dd4148b | |||
| f91d2ed9ae | |||
| 9497463718 | |||
| 46e9ecfcdd | |||
| e9c399c822 | |||
| b9dbfcb4ac | |||
| c270e27a4d | |||
| 0307f604ea | |||
| 8939af48fe | |||
| fa5d58cd00 | |||
| 1a3cf4b3c1 | |||
| 7d96352e96 | |||
| 111ecc5d8c | |||
| edd6fe954b | |||
| a20e9249c5 | |||
| b1353a99cd | |||
| c59e876bb3 | |||
| 7f1e697c0d | |||
| 373edcd055 | |||
| f0b5c4f857 | |||
| 3035d4fa34 | |||
| 60ac737439 | |||
| a95b0d301e | |||
| 951ca5ace0 | |||
| adf05a5bf6 | |||
| 418062165f | |||
| 210373b3b6 | |||
| 5f9fffa53e | |||
| 9cda015733 | |||
| 58a8d22931 | |||
| ef0ed22593 | |||
| 79925ac394 | |||
| b60e4092ec | |||
| fdc36e5c06 | |||
| 49e11ce1ba | |||
| 7ae1b5f8f3 | |||
| 1ac054b34a | |||
| 1e36ef551d | |||
| 0058c7226e | |||
| 29d4f3e887 | |||
| 1b8310d98a | |||
| af4c388dff | |||
| 09f6d9361d | |||
| 1f9eb8300f | |||
| c6a5be7f6a | |||
| 0a06af8d21 | |||
| 3393ad6760 | |||
| 830309fcb5 | |||
| ab4f3f3111 | |||
| 00460b8dee | |||
| d4486be2b9 | |||
| 991e344804 | |||
| 6a7de26e5a | |||
| 5382ef3b0b | |||
| a8cbc9184e | |||
| 966e9ccf0c | |||
| 53ade10137 | |||
| 422c719352 | |||
| 3415619bfd | |||
| 04bb76bc00 | |||
| 8b0f482666 | |||
| 4b3178b053 | |||
| 8e1ae68569 | |||
| 31000e1874 | |||
| 4487cb26c7 | |||
| aba4e18553 | |||
| c82f2580b4 | |||
| 1d7b009aec | |||
| 89c4b02bf3 | |||
| eeb8e44cda | |||
| 785c2d9605 | |||
| d549f048e1 | |||
| 4c0dd63011 | |||
| 26fb134165 | |||
| 07e614b52b | |||
| b1f899fbe8 | |||
| b4f860e627 | |||
| d940fe1b49 | |||
| f2899a9e06 | |||
| 3aca38d2d3 | |||
| 30752ac4ff | |||
| b84e6ca4f5 | |||
| 87a2fb0f1a | |||
| 9eaf7b9824 | |||
| 7bde100237 | |||
| da7fc795ee | |||
| 4c5fec1363 | |||
| 6588b0ad37 | |||
| 0093f74cfe | |||
| 171c6da57a | |||
| 2dddc7796d | |||
| 8514f4119a | |||
| 98fb7d94aa | |||
| 31ca16d9bc | |||
| 9f72ce695e | |||
| c383e4f953 | |||
| a94d8750fb | |||
| b0d651be40 | |||
| d5a9c11b5c | |||
| 6bfe1c435a | |||
| a02da49b87 | |||
| 29dc6c3367 | |||
| a7f0bab078 | |||
| 3dc6829303 | |||
| 42e63ff942 | |||
| df07751e6f | |||
| 5445f1741b | |||
| 9d0f811221 | |||
| 36b9a859c4 | |||
| 59628d1712 | |||
| bee7470715 | |||
| 5a359e10f4 | |||
| 5e37ade519 | |||
| 1a9ffdbd0c | |||
| 2adb0e99b0 | |||
| 71ed1f2f12 | |||
| 47954502af | |||
| 4987fd15f7 | |||
| 8bfe0d0ac0 | |||
| 7c0e6bd18f | |||
| 41b9c33c2b | |||
| 28a775db22 | |||
| e999600f8f | |||
| d3492d8d36 | |||
| 48de0c51b0 | |||
| 93bda5f1dc | |||
| 2d75ef6b30 | |||
| f97160f715 | |||
| eb59c776ca | |||
| 9128201c78 | |||
| 2cbfd37072 | |||
| 0939214c51 | |||
| 8c60f5aea7 | |||
| da0ed4021d | |||
| 99f905403b | |||
| aa0654332d | |||
| af376c22c3 | |||
| 477eb7b70e | |||
| 026e91a68c | |||
| bfbedac919 | |||
| 4036ff88ed | |||
| 1b4da41f97 | |||
| f61d452814 | |||
| f9866097a0 | |||
| 8b769fcc20 | |||
| 9c954264f4 | |||
| 77a6a9d4e1 | |||
| 547d843cca | |||
| 005cb84593 | |||
| fd5b5e9aa5 | |||
| 0647a7c1fe | |||
| 85c73ef8de | |||
| 5ba1796a7e | |||
| e52b7b380f | |||
| 84c7419652 | |||
| 536221b1f9 | |||
| fc55ac70d3 | |||
| 2afe5b4ef9 | |||
| b4ec2595c9 | |||
| c3ac7b675a | |||
| 24614e44bf | |||
| 9b868ef831 | |||
| c3eaf76430 | |||
| 32958dec3b | |||
| d64a97ba1e | |||
| c3df3372a1 | |||
| 8764353fe2 | |||
| e08c5de5dd | |||
| 74b538b8ec | |||
| 291ec50d98 | |||
| bc5af506bd | |||
| 21c7fd1bd5 | |||
| 28a092261b | |||
| 18dcae0a77 | |||
| 58c307f9cc | |||
| 8cc4809414 | |||
| 1179158def | |||
| 91aa40e749 | |||
| 595019e979 | |||
| b0d7917f88 | |||
| 8e6637a1e4 | |||
| 694fe05953 | |||
| f3dfd2a237 | |||
| 9e6158e9e6 | |||
| d577c4a2ce | |||
| fee0b82a40 | |||
| 7aafa26314 | |||
| d5bc546ca5 | |||
| 45ae217728 | |||
| b7b97dda73 | |||
| 5d3c563d46 | |||
| 376185458b | |||
| a8f14840ab | |||
| 9e32a40b1c | |||
| 87f635e54d | |||
| d4b2dfbde2 | |||
| f6ab0bc56f | |||
| 48cc2a6327 | |||
| 3202a6858a | |||
| b4f1bc16ff | |||
| 029ab46f71 | |||
| 220ca0ca9d | |||
| 20306f493a | |||
| cc865ac523 | |||
| 2d973c1805 | |||
| 6ca499b2dd | |||
| 1477028717 | |||
| 789740be0d | |||
| 8fe7539bb2 | |||
| f6623a3654 | |||
| c4fb923335 | |||
| 65b7eea775 | |||
| 01cd696fd1 | |||
| c13b3f7e68 | |||
| a6571ee0da | |||
| 6e38afff49 | |||
| 3d1b19ed90 | |||
| 5b24f88e73 | |||
| 74d06708dd | |||
| 3bfab6ef7f | |||
| 364cd8d8f7 | |||
| 9f8c579bf5 | |||
| eae7c2d684 | |||
| 3f43fca90d | |||
| 76449488ca | |||
| 00c4b0cef8 | |||
| 89139e2c11 | |||
| c9cab490f7 | |||
| 5fa711d75d | |||
| f5d8ae423a | |||
| 1d54973b92 | |||
| b8fafefd85 | |||
| c42ebb8839 | |||
| 9e680620b5 | |||
| 846f865de2 | |||
| ede9762a58 | |||
| d438c2d67b | |||
| bef110b92a | |||
| b971ef11d1 | |||
| 29d9f69399 | |||
| aecb4083bd | |||
| 1c675ab3a3 | |||
| dd619630a3 | |||
| 111803ab07 | |||
| 0024f74f34 | |||
| 03eec42c33 | |||
| 196f311ae2 | |||
| 38d9e0b209 | |||
| 6502b31316 | |||
| 6f1a8c3115 | |||
| d883c94cc9 | |||
| 961fa59a74 | |||
| 8bc71def55 | |||
| 7c65a9dc0e | |||
| d2d977a6c6 | |||
| a9a6ee9d7f | |||
| 28c5d215c1 | |||
| 3d6a789562 | |||
| a0e68698e3 | |||
| 44613c7d01 | |||
| c706281df3 | |||
| 65d75b8fe3 | |||
| 332b0cba40 | |||
| 8c4af41296 | |||
| 24a78f071b | |||
| c91c33436d | |||
| 2083f43a28 | |||
| 4676abdc9e | |||
| 35700eb23e | |||
| 59892e7b58 | |||
| 97dd07a7d1 | |||
| c8bc97c81b | |||
| 9dacfbbd69 | |||
| 05c2509d07 | |||
| 64f949b37b | |||
| 3f339de36a | |||
| 215c2b71ef | |||
| ce8fef7e0b | |||
| 0726b2c479 | |||
| 589549d7e6 | |||
| edb1a586d8 | |||
| 11c2917040 | |||
| 6ba9c12ff6 | |||
| d2fcc346b9 | |||
| a091a07aa2 | |||
| bb4135cae8 | |||
| 8de84b7ca3 | |||
| 9cdf332029 | |||
| e94fc65f01 | |||
| b908487476 | |||
| 2a7c7faeb4 | |||
| e302e15eea | |||
| 1cbea892cf | |||
| 37a32857a2 | |||
| 8c4aad3a59 | |||
| 1774794b19 | |||
| 1af23f1f2d | |||
| 94fbc3d388 | |||
| 8da2058e2a | |||
| 09993a904a | |||
| 5d1403461c | |||
| ddc1ee564b | |||
| 00a54b848a | |||
| dad15b9fd0 | |||
| d89c19f903 | |||
| 146dc0fad5 | |||
| d26852deef | |||
| e1c27243b2 | |||
| dbbfe7abe2 | |||
| dc24d12ce0 | |||
| 4e7533e872 | |||
| 6a097eca93 | |||
| 84d1c5385d |
@@ -0,0 +1 @@
|
||||
github: dtolnay
|
||||
+48
-25
@@ -18,16 +18,22 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd test_suite && cargo test --features unstable
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: Cargo.lock
|
||||
path: Cargo.lock
|
||||
continue-on-error: true
|
||||
|
||||
windows:
|
||||
name: Test suite (windows)
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
|
||||
|
||||
@@ -40,15 +46,16 @@ jobs:
|
||||
rust: [stable, beta]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd test_suite/no_std && cargo build
|
||||
|
||||
nightly:
|
||||
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
|
||||
name: Rust nightly${{matrix.os == 'windows' && ' (windows)' || ''}}
|
||||
runs-on: ${{matrix.os}}-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -56,14 +63,14 @@ jobs:
|
||||
os: [ubuntu, windows]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd serde && cargo build
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde && cargo build --no-default-features --features alloc
|
||||
- run: cd serde && cargo build --no-default-features --features rc,alloc
|
||||
- run: cd serde && cargo build --no-default-features --features unstable
|
||||
- run: cd serde && cargo test --features derive,rc,unstable
|
||||
- run: cd serde_core && cargo test --features rc,unstable
|
||||
- run: cd test_suite/no_std && cargo build
|
||||
if: matrix.os != 'windows'
|
||||
- run: cd serde_derive && cargo check --tests
|
||||
@@ -77,56 +84,69 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [1.31.0, 1.34.0]
|
||||
rust: [1.56.0, 1.60.0]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
- run: sed -i '/"test_suite"/d' Cargo.toml
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde && cargo build --no-default-features --features alloc
|
||||
- run: cd serde && cargo build
|
||||
|
||||
derive:
|
||||
name: Rust 1.56.0
|
||||
name: Rust 1.61.0
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@1.56.0
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@1.61.0
|
||||
- run: |
|
||||
sed -i 's/proc-macro2 = { workspace = true/proc-macro2 = { version = "1"/' serde_derive*/Cargo.toml
|
||||
sed -i 's/quote = { workspace = true/quote = { version = "1"/' serde_derive*/Cargo.toml
|
||||
sed -i 's/syn = { workspace = true/syn = { version = "2"/' serde_derive*/Cargo.toml
|
||||
- run: cd serde && cargo check --no-default-features
|
||||
- run: cd serde && cargo check
|
||||
- run: cd serde_derive && cargo check
|
||||
|
||||
alloc:
|
||||
name: Rust 1.36.0
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dtolnay/rust-toolchain@1.36.0
|
||||
- run: cd serde && cargo build --no-default-features --features alloc
|
||||
|
||||
minimal:
|
||||
name: Minimal versions
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo generate-lockfile -Z minimal-versions
|
||||
- run: cargo check --locked --workspace
|
||||
|
||||
doc:
|
||||
name: Documentation
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
RUSTDOCFLAGS: -Dwarnings
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: dtolnay/install@cargo-docs-rs
|
||||
- run: cargo docs-rs -p serde
|
||||
- run: cargo docs-rs -p serde_core
|
||||
- run: cargo docs-rs -p serde_derive
|
||||
- run: cargo docs-rs -p serde_derive_internals
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@clippy
|
||||
- run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cd serde_core && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cd serde_derive && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
|
||||
@@ -137,10 +157,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@miri
|
||||
with:
|
||||
toolchain: nightly-2025-05-16 # https://github.com/rust-lang/miri/issues/4323
|
||||
- run: cargo miri setup
|
||||
- run: cd serde && cargo miri test --features derive,rc,unstable
|
||||
- run: cd serde_core && cargo miri test --features rc,unstable
|
||||
env:
|
||||
MIRIFLAGS: -Zmiri-strict-provenance
|
||||
- run: cd test_suite && cargo miri test --features unstable
|
||||
@@ -153,6 +175,7 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/install@cargo-outdated
|
||||
- run: cargo outdated --workspace --exit-code 1
|
||||
|
||||
+2
-4
@@ -1,4 +1,2 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.sw[po]
|
||||
Cargo.lock
|
||||
/target/
|
||||
/Cargo.lock
|
||||
|
||||
+3
-3
@@ -27,11 +27,11 @@ pull request with your changes. If anything does not pass, typically it will be
|
||||
easier to iterate and fix it locally than waiting for the CI servers to run
|
||||
tests for you.
|
||||
|
||||
##### In the [`serde`] directory
|
||||
##### In the [`serde_core`] directory
|
||||
|
||||
```sh
|
||||
# Test all the example code in Serde documentation
|
||||
cargo test --features derive
|
||||
cargo test
|
||||
```
|
||||
|
||||
##### In the [`test_suite`] directory
|
||||
@@ -43,7 +43,7 @@ cargo +nightly test --features unstable
|
||||
|
||||
Note that this test suite currently only supports running on a nightly compiler.
|
||||
|
||||
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
|
||||
[`serde_core`]: https://github.com/serde-rs/serde/tree/master/serde_core
|
||||
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
|
||||
|
||||
## Conduct
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
"serde_derive_internals",
|
||||
"test_suite",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[patch.crates-io]
|
||||
serde = { path = "serde" }
|
||||
serde_core = { path = "serde_core" }
|
||||
serde_derive = { path = "serde_derive" }
|
||||
|
||||
[workspace.dependencies]
|
||||
proc-macro2 = { version = "1.0.74", default-features = false }
|
||||
quote = { version = "1.0.35", default-features = false }
|
||||
syn = { version = "2.0.81", default-features = false }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.31+]][Rust 1.31] [![serde_derive: rustc 1.56+]][Rust 1.56]
|
||||
# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.56] [![serde_derive msrv]][Rust 1.61]
|
||||
|
||||
[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master
|
||||
[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster
|
||||
[Latest Version]: https://img.shields.io/crates/v/serde.svg
|
||||
[crates.io]: https://crates.io/crates/serde
|
||||
[serde: rustc 1.31+]: https://img.shields.io/badge/serde-rustc_1.31+-lightgray.svg
|
||||
[serde_derive: rustc 1.56+]: https://img.shields.io/badge/serde_derive-rustc_1.56+-lightgray.svg
|
||||
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
|
||||
[serde msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray
|
||||
[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray
|
||||
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html
|
||||
[Rust 1.61]: https://blog.rust-lang.org/2022/05/19/Rust-1.61.0.html
|
||||
|
||||
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
You may be looking for:
|
||||
|
||||
- [An overview of Serde](https://serde.rs/)
|
||||
- [An overview of Serde](https://serde.rs)
|
||||
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||
- [Examples](https://serde.rs/examples.html)
|
||||
@@ -27,7 +27,7 @@ You may be looking for:
|
||||
<details>
|
||||
<summary>
|
||||
Click to show Cargo.toml.
|
||||
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||
<a href="https://play.rust-lang.org/?edition=2021&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||
</summary>
|
||||
|
||||
```toml
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@
|
||||
|
||||
You may be looking for:
|
||||
|
||||
- [An overview of Serde](https://serde.rs/)
|
||||
- [An overview of Serde](https://serde.rs)
|
||||
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||
- [Examples](https://serde.rs/examples.html)
|
||||
@@ -46,8 +46,8 @@ fn main() {
|
||||
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
||||
congregate will be able to help you out. For chat, consider trying the
|
||||
[#rust-questions] or [#rust-beginners] channels of the unofficial community
|
||||
Discord (invite: <https://discord.gg/rust-lang-community>, the [#rust-usage] or
|
||||
[#beginners] channels of the official Rust Project Discord (invite:
|
||||
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage]
|
||||
or [#beginners] channels of the official Rust Project Discord (invite:
|
||||
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
|
||||
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
|
||||
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
|
||||
|
||||
+16
-23
@@ -1,43 +1,36 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.186" # remember to update html_root_url and serde_derive dependency
|
||||
version = "1.0.227"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
build = "build.rs"
|
||||
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||
description = "A generic serialization/deserialization framework"
|
||||
documentation = "https://docs.rs/serde"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
homepage = "https://serde.rs"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "crates-io.md"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
rust-version = "1.31"
|
||||
rust-version = "1.56"
|
||||
|
||||
[dependencies]
|
||||
serde_core = { version = "=1.0.227", path = "../serde_core", default-features = false, features = ["result"] }
|
||||
serde_derive = { version = "1", optional = true, path = "../serde_derive" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = { version = "1", path = "../serde_derive" }
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["derive", "rc"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["derive"]
|
||||
features = ["derive", "rc", "unstable"]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
# This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's
|
||||
# version in lockstep with serde's, even if someone depends on the two crates
|
||||
# separately with serde's "derive" feature disabled. Every serde_derive release
|
||||
# is compatible with exactly one serde release because the generated code
|
||||
# involves nonpublic APIs which are not bound by semver.
|
||||
[target.'cfg(any())'.dependencies]
|
||||
serde_derive = { version = "=1.0.186", path = "../serde_derive" }
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
|
||||
### FEATURES #################################################################
|
||||
@@ -50,20 +43,20 @@ derive = ["serde_derive"]
|
||||
|
||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||
# Requires a dependency on the Rust standard library.
|
||||
std = []
|
||||
std = ["serde_core/std"]
|
||||
|
||||
# Provide impls for types that require unstable functionality. For tracking and
|
||||
# discussion of unstable functionality please refer to this issue:
|
||||
#
|
||||
# https://github.com/serde-rs/serde/issues/812
|
||||
unstable = []
|
||||
unstable = ["serde_core/unstable"]
|
||||
|
||||
# Provide impls for types in the Rust core allocation and collections library
|
||||
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
|
||||
# be enabled without depending on all of std.
|
||||
alloc = []
|
||||
alloc = ["serde_core/alloc"]
|
||||
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
rc = []
|
||||
rc = ["serde_core/rc"]
|
||||
|
||||
+43
-69
@@ -1,6 +1,17 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::str::{self, FromStr};
|
||||
use std::str;
|
||||
|
||||
const PRIVATE: &str = "\
|
||||
#[doc(hidden)]
|
||||
pub mod __private$$ {
|
||||
#[doc(hidden)]
|
||||
pub use crate::private::*;
|
||||
}
|
||||
use serde_core::__private$$ as serde_core_private;
|
||||
";
|
||||
|
||||
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||
// opening a GitHub issue if your build environment requires some way to enable
|
||||
@@ -8,90 +19,53 @@ use std::str::{self, FromStr};
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
if env::var_os("DOCS_RS").is_some() {
|
||||
println!("cargo:rustc-cfg=no_serde_core");
|
||||
}
|
||||
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap();
|
||||
let module = PRIVATE.replace("$$", &patch_version);
|
||||
fs::write(out_dir.join("private.rs"), module).unwrap();
|
||||
|
||||
let minor = match rustc_minor_version() {
|
||||
Some(minor) => minor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
||||
|
||||
// TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
|
||||
// stabilized in Rust 1.34:
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
|
||||
if minor < 34 {
|
||||
println!("cargo:rustc-cfg=no_core_try_from");
|
||||
println!("cargo:rustc-cfg=no_num_nonzero_signed");
|
||||
println!("cargo:rustc-cfg=no_systemtime_checked_add");
|
||||
println!("cargo:rustc-cfg=no_relaxed_trait_bounds");
|
||||
if minor >= 77 {
|
||||
println!("cargo:rustc-check-cfg=cfg(feature, values(\"result\"))");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_serde_core)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_serde_derive)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_std_atomic)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)");
|
||||
}
|
||||
|
||||
// Disabled on Emscripten targets before Rust 1.40 since
|
||||
// Emscripten did not support 128-bit integers until Rust 1.40
|
||||
// (https://github.com/rust-lang/rust/pull/65251)
|
||||
if emscripten && minor < 40 {
|
||||
println!("cargo:rustc-cfg=no_integer128");
|
||||
}
|
||||
|
||||
// Current minimum supported version of serde_derive crate is Rust 1.56.
|
||||
if minor < 56 {
|
||||
// Current minimum supported version of serde_derive crate is Rust 1.61.
|
||||
if minor < 61 {
|
||||
println!("cargo:rustc-cfg=no_serde_derive");
|
||||
}
|
||||
|
||||
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
|
||||
if minor < 60 {
|
||||
println!("cargo:rustc-cfg=no_target_has_atomic");
|
||||
// Allowlist of archs that support std::sync::atomic module. This is
|
||||
// based on rustc's compiler/rustc_target/src/spec/*.rs.
|
||||
let has_atomic64 = target.starts_with("x86_64")
|
||||
|| target.starts_with("i686")
|
||||
|| target.starts_with("aarch64")
|
||||
|| target.starts_with("powerpc64")
|
||||
|| target.starts_with("sparc64")
|
||||
|| target.starts_with("mips64el")
|
||||
|| target.starts_with("riscv64");
|
||||
let has_atomic32 = has_atomic64 || emscripten;
|
||||
if minor < 34 || !has_atomic64 {
|
||||
println!("cargo:rustc-cfg=no_std_atomic64");
|
||||
}
|
||||
if minor < 34 || !has_atomic32 {
|
||||
println!("cargo:rustc-cfg=no_std_atomic");
|
||||
}
|
||||
}
|
||||
|
||||
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
|
||||
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
|
||||
if minor < 64 {
|
||||
println!("cargo:rustc-cfg=no_core_cstr");
|
||||
// Support for the `#[diagnostic]` tool attribute namespace
|
||||
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
|
||||
if minor < 78 {
|
||||
println!("cargo:rustc-cfg=no_diagnostic_namespace");
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = match env::var_os("RUSTC") {
|
||||
Some(rustc) => rustc,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let output = match Command::new(rustc).arg("--version").output() {
|
||||
Ok(output) => output,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let version = match str::from_utf8(&output.stdout) {
|
||||
Ok(version) => version,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let next = match pieces.next() {
|
||||
Some(next) => next,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
u32::from_str(next).ok()
|
||||
pieces.next()?.parse().ok()
|
||||
}
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../serde_core/src
|
||||
+8
-76
@@ -1,82 +1,14 @@
|
||||
/// Conditional compilation depending on whether Serde is built with support for
|
||||
/// 128-bit integers.
|
||||
///
|
||||
/// Data formats that wish to support Rust compiler versions older than 1.26
|
||||
/// (or targets that lack 128-bit integers) may place the i128 / u128 methods
|
||||
/// of their Serializer and Deserializer behind this macro.
|
||||
///
|
||||
/// Data formats that require a minimum Rust compiler version of at least 1.26,
|
||||
/// or do not target platforms that lack 128-bit integers, do not need to
|
||||
/// bother with this macro and may assume support for 128-bit integers.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
/// use serde::{serde_if_integer128, Serializer};
|
||||
///
|
||||
/// impl Serializer for MySerializer {
|
||||
/// type Ok = ();
|
||||
/// type Error = Error;
|
||||
///
|
||||
/// fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// /* ... */
|
||||
///
|
||||
/// serde_if_integer128! {
|
||||
/// fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # serde::__serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant seq
|
||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When Serde is built with support for 128-bit integers, this macro expands
|
||||
/// transparently into just the input tokens.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {
|
||||
/// $($tt)*
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When built without support for 128-bit integers, this macro expands to
|
||||
/// nothing.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {};
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(not(no_integer128))]
|
||||
#[macro_export]
|
||||
#[deprecated = "
|
||||
This macro has no effect on any version of Serde released in the past 2 years.
|
||||
It was used long ago in crates that needed to support Rustc older than 1.26.0,
|
||||
or Emscripten targets older than 1.40.0, which did not yet have 128-bit integer
|
||||
support. These days Serde requires a Rust compiler newer than that so 128-bit
|
||||
integers are always supported.
|
||||
"]
|
||||
#[doc(hidden)]
|
||||
macro_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {
|
||||
$($tt)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(no_integer128)]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {};
|
||||
}
|
||||
|
||||
+115
-157
@@ -9,7 +9,7 @@
|
||||
//! these two groups interact with each other, allowing any supported data
|
||||
//! structure to be serialized and deserialized using any supported data format.
|
||||
//!
|
||||
//! See the Serde website <https://serde.rs/> for additional documentation and
|
||||
//! See the Serde website <https://serde.rs> for additional documentation and
|
||||
//! usage examples.
|
||||
//!
|
||||
//! ## Design
|
||||
@@ -63,6 +63,7 @@
|
||||
//! and from DynamoDB.
|
||||
//! - [Hjson], a syntax extension to JSON designed around human reading and
|
||||
//! editing. *(deserialization only)*
|
||||
//! - [CSV], Comma-separated values is a tabular text file format.
|
||||
//!
|
||||
//! [JSON]: https://github.com/serde-rs/json
|
||||
//! [Postcard]: https://github.com/jamesmunns/postcard
|
||||
@@ -89,19 +90,28 @@
|
||||
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
|
||||
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb
|
||||
//! [Hjson]: https://github.com/Canop/deser-hjson
|
||||
//! [CSV]: https://docs.rs/csv
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.186")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.227")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// Show which crate feature enables conditionally compiled APIs in documentation.
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))]
|
||||
#![cfg_attr(docsrs, allow(internal_features))]
|
||||
// Unstable functionality only if the user asks for it. For tracking and
|
||||
// discussion of these features please refer to this issue:
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(error_in_core, never_type))]
|
||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
#![allow(
|
||||
unknown_lints,
|
||||
bare_trait_objects,
|
||||
deprecated,
|
||||
mismatched_lifetime_syntaxes
|
||||
)]
|
||||
// Ignored clippy and clippy_pedantic lints
|
||||
#![allow(
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
@@ -114,11 +124,11 @@
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::cast_sign_loss,
|
||||
// things are often more readable this way
|
||||
clippy::cast_lossless,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::option_if_let_else,
|
||||
clippy::single_match_else,
|
||||
clippy::type_complexity,
|
||||
clippy::use_self,
|
||||
@@ -127,6 +137,7 @@
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::enum_glob_use,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::incompatible_msrv,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::map_err_ignore,
|
||||
clippy::new_without_default,
|
||||
@@ -138,6 +149,8 @@
|
||||
clippy::too_many_lines,
|
||||
// preference
|
||||
clippy::doc_markdown,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::unseparated_literal_suffix,
|
||||
// false positive
|
||||
clippy::needless_doctest_main,
|
||||
@@ -155,160 +168,103 @@
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use core::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
|
||||
pub use self::core::{f32, f64};
|
||||
pub use self::core::{i16, i32, i64, i8, isize};
|
||||
pub use self::core::{u16, u32, u64, u8, usize};
|
||||
|
||||
pub use self::core::cell::{Cell, RefCell};
|
||||
pub use self::core::clone::{self, Clone};
|
||||
pub use self::core::cmp::Reverse;
|
||||
pub use self::core::convert::{self, From, Into};
|
||||
pub use self::core::default::{self, Default};
|
||||
pub use self::core::fmt::{self, Debug, Display};
|
||||
pub use self::core::marker::{self, PhantomData};
|
||||
pub use self::core::num::Wrapping;
|
||||
pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo};
|
||||
pub use self::core::option::{self, Option};
|
||||
pub use self::core::result::{self, Result};
|
||||
pub use self::core::time::Duration;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::{String, ToString};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::boxed::Box;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::rc::{Rc, Weak as RcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::rc::{Rc, Weak as RcWeak};
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::sync::{Arc, Weak as ArcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::sync::{Arc, Weak as ArcWeak};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
|
||||
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
|
||||
pub use self::core::ffi::CStr;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::CStr;
|
||||
|
||||
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::ffi::CString;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::CString;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::{error, net};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::{OsStr, OsString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::hash::{BuildHasher, Hash};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::Write;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))]
|
||||
pub use std::sync::atomic::{
|
||||
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
|
||||
AtomicUsize, Ordering,
|
||||
};
|
||||
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))]
|
||||
pub use std::sync::atomic::{AtomicI64, AtomicU64};
|
||||
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic)))]
|
||||
pub use std::sync::atomic::Ordering;
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))]
|
||||
pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))]
|
||||
pub use std::sync::atomic::{AtomicI16, AtomicU16};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))]
|
||||
pub use std::sync::atomic::{AtomicI32, AtomicU32};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))]
|
||||
pub use std::sync::atomic::{AtomicI64, AtomicU64};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))]
|
||||
pub use std::sync::atomic::{AtomicIsize, AtomicUsize};
|
||||
}
|
||||
|
||||
// None of this crate's error handling needs the `From::from` error conversion
|
||||
// performed implicitly by the `?` operator or the standard library's `try!`
|
||||
// macro. This simplified macro gives a 5.5% improvement in compile time
|
||||
// compared to standard `try!`, and 9% improvement compared to `?`.
|
||||
macro_rules! tri {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Rustdoc has a lot of shortcomings related to cross-crate re-exports that make
|
||||
// the rendered documentation of serde_core traits in serde more challenging to
|
||||
// understand than the equivalent documentation of the same items in serde_core.
|
||||
// https://github.com/rust-lang/rust/labels/A-cross-crate-reexports
|
||||
// So, just for the purpose of docs.rs documentation, we inline the contents of
|
||||
// serde_core into serde. This sidesteps all the cross-crate rustdoc bugs.
|
||||
#[cfg(docsrs)]
|
||||
#[macro_use]
|
||||
#[path = "core/crate_root.rs"]
|
||||
mod crate_root;
|
||||
|
||||
#[cfg(docsrs)]
|
||||
#[macro_use]
|
||||
#[path = "core/macros.rs"]
|
||||
mod macros;
|
||||
|
||||
#[macro_use]
|
||||
#[cfg(not(docsrs))]
|
||||
macro_rules! crate_root {
|
||||
() => {
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use core::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
pub use self::core::{f32, f64};
|
||||
pub use self::core::{ptr, str};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub use self::core::slice;
|
||||
|
||||
pub use self::core::clone;
|
||||
pub use self::core::convert;
|
||||
pub use self::core::default;
|
||||
pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite};
|
||||
pub use self::core::marker::{self, PhantomData};
|
||||
pub use self::core::option;
|
||||
pub use self::core::result;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::{String, ToString};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::boxed::Box;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
}
|
||||
|
||||
// None of this crate's error handling needs the `From::from` error conversion
|
||||
// performed implicitly by the `?` operator or the standard library's `try!`
|
||||
// macro. This simplified macro gives a 5.5% improvement in compile time
|
||||
// compared to standard `try!`, and 9% improvement compared to `?`.
|
||||
#[cfg(not(no_serde_derive))]
|
||||
macro_rules! tri {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub use serde_core::{
|
||||
de, forward_to_deserialize_any, ser, Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
// Used by generated code and doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
mod private;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/private.rs"));
|
||||
};
|
||||
}
|
||||
|
||||
crate_root!();
|
||||
|
||||
mod integer128;
|
||||
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::de::{Deserialize, Deserializer};
|
||||
#[doc(inline)]
|
||||
pub use crate::ser::{Serialize, Serializer};
|
||||
|
||||
// Used by generated code and doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
#[path = "private/mod.rs"]
|
||||
pub mod __private;
|
||||
|
||||
#[path = "de/seed.rs"]
|
||||
mod seed;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
||||
mod std_error;
|
||||
|
||||
// Re-export #[derive(Serialize, Deserialize)].
|
||||
//
|
||||
// The reason re-exporting is not enabled by default is that disabling it would
|
||||
@@ -319,9 +275,11 @@ extern crate serde_derive;
|
||||
|
||||
/// Derive macro available if serde is built with `features = ["derive"]`.
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||
pub use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||
mod actually_private {
|
||||
pub struct T;
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __require_serde_not_serde_core {
|
||||
() => {};
|
||||
}
|
||||
|
||||
+919
-310
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,8 @@ pub mod de;
|
||||
#[cfg(not(no_serde_derive))]
|
||||
pub mod ser;
|
||||
|
||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||
pub mod doc;
|
||||
|
||||
pub use crate::lib::clone::Clone;
|
||||
pub use crate::lib::convert::{From, Into};
|
||||
pub use crate::lib::convert::{From, Into, TryFrom};
|
||||
pub use crate::lib::default::Default;
|
||||
pub use crate::lib::fmt::{self, Formatter};
|
||||
pub use crate::lib::marker::PhantomData;
|
||||
@@ -15,34 +12,7 @@ pub use crate::lib::option::Option::{self, None, Some};
|
||||
pub use crate::lib::ptr;
|
||||
pub use crate::lib::result::Result::{self, Err, Ok};
|
||||
|
||||
pub use self::string::from_utf8_lossy;
|
||||
pub use crate::serde_core_private::string::from_utf8_lossy;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub use crate::lib::{ToString, Vec};
|
||||
|
||||
#[cfg(not(no_core_try_from))]
|
||||
pub use crate::lib::convert::TryFrom;
|
||||
|
||||
mod string {
|
||||
use crate::lib::*;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
|
||||
// The generated code calls this like:
|
||||
//
|
||||
// let value = &_serde::__private::from_utf8_lossy(bytes);
|
||||
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
|
||||
//
|
||||
// so it is okay for the return type to be different from the std case as long
|
||||
// as the above works.
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
// Three unicode replacement characters if it fails. They look like a
|
||||
// white-on-black question mark. The user will recognize it as invalid
|
||||
// UTF-8.
|
||||
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
|
||||
}
|
||||
}
|
||||
|
||||
+82
-85
@@ -51,14 +51,14 @@ enum Unsupported {
|
||||
String,
|
||||
ByteArray,
|
||||
Optional,
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
UnitStruct,
|
||||
Sequence,
|
||||
Tuple,
|
||||
TupleStruct,
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
Enum,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl Display for Unsupported {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
@@ -69,11 +69,10 @@ impl Display for Unsupported {
|
||||
Unsupported::String => formatter.write_str("a string"),
|
||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||
Unsupported::Optional => formatter.write_str("an optional"),
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
Unsupported::UnitStruct => formatter.write_str("unit struct"),
|
||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
Unsupported::Enum => formatter.write_str("an enum"),
|
||||
}
|
||||
}
|
||||
@@ -91,6 +90,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<S> Serializer for TaggedSerializer<S>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -174,9 +174,9 @@ where
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn serialize_some<T>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
@@ -205,18 +205,18 @@ where
|
||||
map.end()
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
fn serialize_newtype_struct<T>(
|
||||
self,
|
||||
_: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
_: &'static str,
|
||||
_: u32,
|
||||
@@ -224,7 +224,7 @@ where
|
||||
inner_value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let mut map = tri!(self.delegate.serialize_map(Some(2)));
|
||||
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||
@@ -327,9 +327,9 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn collect_str<T>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display,
|
||||
T: ?Sized + Display,
|
||||
{
|
||||
Err(self.bad_type(Unsupported::String))
|
||||
}
|
||||
@@ -357,6 +357,7 @@ mod content {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
|
||||
where
|
||||
M: ser::SerializeMap,
|
||||
@@ -364,9 +365,9 @@ mod content {
|
||||
type Ok = M::Ok;
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), M::Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), M::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push(value);
|
||||
@@ -397,6 +398,7 @@ mod content {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
|
||||
where
|
||||
M: ser::SerializeMap,
|
||||
@@ -404,13 +406,9 @@ mod content {
|
||||
type Ok = M::Ok;
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), M::Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), M::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push((key, value));
|
||||
@@ -468,6 +466,7 @@ mod content {
|
||||
),
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl Serialize for Content {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -560,6 +559,7 @@ mod content {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> Serializer for ContentSerializer<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -635,9 +635,9 @@ mod content {
|
||||
Ok(Content::None)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Content, E>
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Content, E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Ok(Content::Some(Box::new(tri!(value.serialize(self)))))
|
||||
}
|
||||
@@ -659,13 +659,9 @@ mod content {
|
||||
Ok(Content::UnitVariant(name, variant_index, variant))
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Content, E>
|
||||
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Content, E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Ok(Content::NewtypeStruct(
|
||||
name,
|
||||
@@ -673,7 +669,7 @@ mod content {
|
||||
))
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
@@ -681,7 +677,7 @@ mod content {
|
||||
value: &T,
|
||||
) -> Result<Content, E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Ok(Content::NewtypeVariant(
|
||||
name,
|
||||
@@ -775,6 +771,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeSeq for SerializeSeq<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -782,9 +779,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.elements.push(value);
|
||||
@@ -801,6 +798,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeTuple for SerializeTuple<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -808,9 +806,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.elements.push(value);
|
||||
@@ -828,6 +826,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -835,9 +834,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push(value);
|
||||
@@ -857,6 +856,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -864,9 +864,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push(value);
|
||||
@@ -889,6 +889,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeMap for SerializeMap<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -896,18 +897,18 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), E>
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let key = tri!(key.serialize(ContentSerializer::<E>::new()));
|
||||
self.key = Some(key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let key = self
|
||||
.key
|
||||
@@ -922,10 +923,10 @@ mod content {
|
||||
Ok(Content::Map(self.entries))
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<(), E>
|
||||
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), E>
|
||||
where
|
||||
K: Serialize,
|
||||
V: Serialize,
|
||||
K: ?Sized + Serialize,
|
||||
V: ?Sized + Serialize,
|
||||
{
|
||||
let key = tri!(key.serialize(ContentSerializer::<E>::new()));
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
@@ -940,6 +941,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeStruct for SerializeStruct<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -947,9 +949,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push((key, value));
|
||||
@@ -969,6 +971,7 @@ mod content {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
|
||||
where
|
||||
E: ser::Error,
|
||||
@@ -976,9 +979,9 @@ mod content {
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), E>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push((key, value));
|
||||
@@ -1013,6 +1016,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
@@ -1088,9 +1092,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
@@ -1100,30 +1104,30 @@ where
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Self::bad_type(Unsupported::UnitStruct))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
_: u32,
|
||||
_: &'static str,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Self::bad_type(Unsupported::Enum))
|
||||
self.0.serialize_entry(variant, &())
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
fn serialize_newtype_struct<T>(
|
||||
self,
|
||||
_: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
_: &'static str,
|
||||
_: u32,
|
||||
@@ -1131,10 +1135,9 @@ where
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
tri!(self.0.serialize_key(variant));
|
||||
self.0.serialize_value(value)
|
||||
self.0.serialize_entry(variant, value)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
@@ -1195,6 +1198,7 @@ where
|
||||
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
@@ -1202,28 +1206,24 @@ where
|
||||
type Ok = ();
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
self.0.serialize_key(key)
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
self.0.serialize_value(value)
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
||||
&mut self,
|
||||
key: &K,
|
||||
value: &V,
|
||||
) -> Result<(), Self::Error>
|
||||
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
|
||||
where
|
||||
K: Serialize,
|
||||
V: Serialize,
|
||||
K: ?Sized + Serialize,
|
||||
V: ?Sized + Serialize,
|
||||
{
|
||||
self.0.serialize_entry(key, value)
|
||||
}
|
||||
@@ -1237,6 +1237,7 @@ where
|
||||
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
@@ -1244,13 +1245,9 @@ where
|
||||
type Ok = ();
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
self.0.serialize_entry(key, value)
|
||||
}
|
||||
@@ -1282,6 +1279,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, M> ser::SerializeTupleVariant for FlatMapSerializeTupleVariantAsMapValue<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
@@ -1289,9 +1287,9 @@ where
|
||||
type Ok = ();
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push(value);
|
||||
@@ -1328,6 +1326,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
@@ -1335,13 +1334,9 @@ where
|
||||
type Ok = ();
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push((key, value));
|
||||
@@ -1362,6 +1357,7 @@ pub struct AdjacentlyTaggedEnumVariant {
|
||||
pub variant_name: &'static str,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl Serialize for AdjacentlyTaggedEnumVariant {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -1375,6 +1371,7 @@ impl Serialize for AdjacentlyTaggedEnumVariant {
|
||||
// that is not recognized.
|
||||
pub struct CannotSerializeVariant<T>(pub T);
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<T> Display for CannotSerializeVariant<T>
|
||||
where
|
||||
T: Debug,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
[package]
|
||||
name = "serde_core"
|
||||
version = "1.0.227"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
build = "build.rs"
|
||||
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||
description = "Serde traits only, with no support for derive -- use the `serde` crate instead"
|
||||
documentation = "https://docs.rs/serde_core"
|
||||
edition = "2021"
|
||||
homepage = "https://serde.rs"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
rust-version = "1.56"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1", path = "../serde" }
|
||||
serde_derive = { version = "1", path = "../serde_derive" }
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["rc", "result"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["rc", "result", "unstable"]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
# This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's
|
||||
# version in lockstep with serde's, even if someone depends on the two crates
|
||||
# separately with serde's "derive" feature disabled. Every serde_derive release
|
||||
# is compatible with exactly one serde release because the generated code
|
||||
# involves nonpublic APIs which are not bound by semver.
|
||||
[target.'cfg(any())'.dependencies]
|
||||
serde_derive = { version = "=1.0.227", path = "../serde_derive" }
|
||||
|
||||
|
||||
### FEATURES #################################################################
|
||||
|
||||
[features]
|
||||
default = ["std", "result"]
|
||||
|
||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||
# Requires a dependency on the Rust standard library.
|
||||
std = []
|
||||
|
||||
# Provide impls for types that require unstable functionality. For tracking and
|
||||
# discussion of unstable functionality please refer to this issue:
|
||||
#
|
||||
# https://github.com/serde-rs/serde/issues/812
|
||||
unstable = []
|
||||
|
||||
# Provide impls for types in the Rust core allocation and collections library
|
||||
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
|
||||
# be enabled without depending on all of std.
|
||||
alloc = []
|
||||
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
rc = []
|
||||
|
||||
# Provide impls for Result<T, E>. Convenient in some contexts but can lead to
|
||||
# confusion if ? or unwrap are used incautiously.
|
||||
result = []
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../LICENSE-APACHE
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../LICENSE-MIT
|
||||
@@ -0,0 +1,28 @@
|
||||
The `serde_core` crate contains Serde's trait definitions with **no support for
|
||||
#\[derive()\]**.
|
||||
|
||||
In crates that derive an implementation of `Serialize` or `Deserialize`, you
|
||||
must depend on the [`serde`] crate, not `serde_core`.
|
||||
|
||||
[`serde`]: https://crates.io/crates/serde
|
||||
|
||||
In crates that handwrite implementations of Serde traits, or only use them as
|
||||
trait bounds, depending on `serde_core` is permitted. But `serde` re-exports all
|
||||
of these traits and can be used for this use case too. If in doubt, disregard
|
||||
`serde_core` and always use `serde`.
|
||||
|
||||
Crates that depend on `serde_core` instead of `serde` are able to compile in
|
||||
parallel with `serde_derive` even when `serde`'s "derive" feature is turned on,
|
||||
as shown in the following build timings.
|
||||
|
||||
<br>
|
||||
|
||||
| When `serde_json` depends on `serde` |
|
||||
|---|
|
||||
| <img src="https://github.com/user-attachments/assets/78dc179c-6ab1-4059-928c-1474b0d9d0bb"> |
|
||||
|
||||
<br>
|
||||
|
||||
| When `serde_json` depends on `serde_core` |
|
||||
|---|
|
||||
| <img src="https://github.com/user-attachments/assets/6b6cff5e-3e45-4ac7-9db1-d99ee8b9f5f7"> |
|
||||
@@ -0,0 +1,113 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
const PRIVATE: &str = "\
|
||||
#[doc(hidden)]
|
||||
pub mod __private$$ {
|
||||
#[doc(hidden)]
|
||||
pub use crate::private::*;
|
||||
}
|
||||
";
|
||||
|
||||
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||
// opening a GitHub issue if your build environment requires some way to enable
|
||||
// these cfgs other than by executing our build script.
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap();
|
||||
let module = PRIVATE.replace("$$", &patch_version);
|
||||
fs::write(out_dir.join("private.rs"), module).unwrap();
|
||||
|
||||
let minor = match rustc_minor_version() {
|
||||
Some(minor) => minor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if minor >= 77 {
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_serde_core)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_serde_derive)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_std_atomic)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_std_atomic64)");
|
||||
println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)");
|
||||
}
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
||||
|
||||
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
|
||||
if minor < 60 {
|
||||
println!("cargo:rustc-cfg=no_target_has_atomic");
|
||||
// Allowlist of archs that support std::sync::atomic module. This is
|
||||
// based on rustc's compiler/rustc_target/src/spec/*.rs.
|
||||
let has_atomic64 = target.starts_with("x86_64")
|
||||
|| target.starts_with("i686")
|
||||
|| target.starts_with("aarch64")
|
||||
|| target.starts_with("powerpc64")
|
||||
|| target.starts_with("sparc64")
|
||||
|| target.starts_with("mips64el")
|
||||
|| target.starts_with("riscv64");
|
||||
let has_atomic32 = has_atomic64 || emscripten;
|
||||
if minor < 34 || !has_atomic64 {
|
||||
println!("cargo:rustc-cfg=no_std_atomic64");
|
||||
}
|
||||
if minor < 34 || !has_atomic32 {
|
||||
println!("cargo:rustc-cfg=no_std_atomic");
|
||||
}
|
||||
}
|
||||
|
||||
// Current minimum supported version of serde_derive crate is Rust 1.61.
|
||||
if minor < 61 {
|
||||
println!("cargo:rustc-cfg=no_serde_derive");
|
||||
}
|
||||
|
||||
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
|
||||
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
|
||||
if minor < 64 {
|
||||
println!("cargo:rustc-cfg=no_core_cstr");
|
||||
}
|
||||
|
||||
// Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74
|
||||
// https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis
|
||||
if minor < 74 {
|
||||
println!("cargo:rustc-cfg=no_core_num_saturating");
|
||||
}
|
||||
|
||||
// Support for core::net stabilized in Rust 1.77.
|
||||
// https://blog.rust-lang.org/2024/03/21/Rust-1.77.0.html
|
||||
if minor < 77 {
|
||||
println!("cargo:rustc-cfg=no_core_net");
|
||||
}
|
||||
|
||||
// Support for the `#[diagnostic]` tool attribute namespace
|
||||
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
|
||||
if minor < 78 {
|
||||
println!("cargo:rustc-cfg=no_diagnostic_namespace");
|
||||
}
|
||||
|
||||
// The Error trait became available in core in 1.81.
|
||||
// https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
|
||||
if minor < 81 {
|
||||
println!("cargo:rustc-cfg=no_core_error");
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
pieces.next()?.parse().ok()
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
macro_rules! crate_root {
|
||||
() => {
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use core::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
pub use self::core::{f32, f64};
|
||||
pub use self::core::{iter, num, str};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub use self::core::{cmp, mem};
|
||||
|
||||
pub use self::core::cell::{Cell, RefCell};
|
||||
pub use self::core::cmp::Reverse;
|
||||
pub use self::core::fmt::{self, Debug, Display, Write as FmtWrite};
|
||||
pub use self::core::marker::PhantomData;
|
||||
pub use self::core::num::Wrapping;
|
||||
pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo};
|
||||
pub use self::core::result;
|
||||
pub use self::core::time::Duration;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::{String, ToString};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::boxed::Box;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::rc::{Rc, Weak as RcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::rc::{Rc, Weak as RcWeak};
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::sync::{Arc, Weak as ArcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::sync::{Arc, Weak as ArcWeak};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
|
||||
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
|
||||
pub use self::core::ffi::CStr;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::CStr;
|
||||
|
||||
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::ffi::CString;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::CString;
|
||||
|
||||
#[cfg(all(not(no_core_net), not(feature = "std")))]
|
||||
pub use self::core::net;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::net;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::error;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::{OsStr, OsString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::hash::{BuildHasher, Hash};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::Write;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))]
|
||||
pub use std::sync::atomic::{
|
||||
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
|
||||
AtomicU8, AtomicUsize, Ordering,
|
||||
};
|
||||
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic64)))]
|
||||
pub use std::sync::atomic::{AtomicI64, AtomicU64};
|
||||
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic)))]
|
||||
pub use std::sync::atomic::Ordering;
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "8"))]
|
||||
pub use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "16"))]
|
||||
pub use std::sync::atomic::{AtomicI16, AtomicU16};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "32"))]
|
||||
pub use std::sync::atomic::{AtomicI32, AtomicU32};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "64"))]
|
||||
pub use std::sync::atomic::{AtomicI64, AtomicU64};
|
||||
#[cfg(all(feature = "std", not(no_target_has_atomic), target_has_atomic = "ptr"))]
|
||||
pub use std::sync::atomic::{AtomicIsize, AtomicUsize};
|
||||
|
||||
#[cfg(not(no_core_num_saturating))]
|
||||
pub use self::core::num::Saturating;
|
||||
}
|
||||
|
||||
// None of this crate's error handling needs the `From::from` error conversion
|
||||
// performed implicitly by the `?` operator or the standard library's `try!`
|
||||
// macro. This simplified macro gives a 5.5% improvement in compile time
|
||||
// compared to standard `try!`, and 9% improvement compared to `?`.
|
||||
macro_rules! tri {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg_attr(no_serde_core, path = "core/de/mod.rs")]
|
||||
pub mod de;
|
||||
#[cfg_attr(no_serde_core, path = "core/ser/mod.rs")]
|
||||
pub mod ser;
|
||||
|
||||
#[cfg_attr(no_serde_core, path = "core/format.rs")]
|
||||
mod format;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::de::{Deserialize, Deserializer};
|
||||
#[doc(inline)]
|
||||
pub use crate::ser::{Serialize, Serializer};
|
||||
|
||||
// Used by generated code. Not public API.
|
||||
#[doc(hidden)]
|
||||
#[cfg_attr(no_serde_core, path = "core/private/mod.rs")]
|
||||
mod private;
|
||||
|
||||
// Used by declarative macro generated code. Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
#[doc(hidden)]
|
||||
pub use crate::private::doc;
|
||||
#[doc(hidden)]
|
||||
pub use core::result::Result;
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/private.rs"));
|
||||
|
||||
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||
#[cfg_attr(no_serde_core, path = "core/std_error.rs")]
|
||||
mod std_error;
|
||||
};
|
||||
}
|
||||
@@ -129,12 +129,10 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
#[inline]
|
||||
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -143,12 +141,10 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
#[inline]
|
||||
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,8 +64,8 @@
|
||||
//! - RefCell\<T\>
|
||||
//! - Mutex\<T\>
|
||||
//! - RwLock\<T\>
|
||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Rc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - **Collection types**:
|
||||
//! - BTreeMap\<K, V\>
|
||||
//! - BTreeSet\<T\>
|
||||
@@ -101,8 +101,8 @@
|
||||
//! - SocketAddrV6
|
||||
//!
|
||||
//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html
|
||||
//! [`Deserialize`]: ../trait.Deserialize.html
|
||||
//! [`Deserializer`]: ../trait.Deserializer.html
|
||||
//! [`Deserialize`]: crate::Deserialize
|
||||
//! [`Deserializer`]: crate::Deserializer
|
||||
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
|
||||
//! [`postcard`]: https://github.com/jamesmunns/postcard
|
||||
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
||||
@@ -118,18 +118,14 @@ use crate::lib::*;
|
||||
|
||||
pub mod value;
|
||||
|
||||
#[cfg(not(no_integer128))]
|
||||
mod format;
|
||||
mod ignored_any;
|
||||
mod impls;
|
||||
pub(crate) mod size_hint;
|
||||
|
||||
pub use self::ignored_any::IgnoredAny;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
||||
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::std_error::Error as StdError;
|
||||
#[cfg(all(feature = "unstable", not(feature = "std")))]
|
||||
#[cfg(not(any(feature = "std", no_core_error)))]
|
||||
#[doc(no_inline)]
|
||||
pub use core::error::Error as StdError;
|
||||
#[cfg(feature = "std")]
|
||||
@@ -160,6 +156,12 @@ macro_rules! declare_error_trait {
|
||||
/// type appropriate for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::Error` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Error: Sized $(+ $($supertrait)::+)* {
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
///
|
||||
@@ -208,7 +210,7 @@ macro_rules! declare_error_trait {
|
||||
/// containing an integer, the unexpected type is the integer and the
|
||||
/// expected type is the string.
|
||||
#[cold]
|
||||
fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self {
|
||||
fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self {
|
||||
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
|
||||
}
|
||||
|
||||
@@ -226,7 +228,7 @@ macro_rules! declare_error_trait {
|
||||
/// that is not valid UTF-8, the unexpected value is the bytes and the
|
||||
/// expected value is a string.
|
||||
#[cold]
|
||||
fn invalid_value(unexp: Unexpected, exp: &Expected) -> Self {
|
||||
fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self {
|
||||
Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp))
|
||||
}
|
||||
|
||||
@@ -240,7 +242,7 @@ macro_rules! declare_error_trait {
|
||||
/// expected. For example `exp` might say that a tuple of size 6 was
|
||||
/// expected.
|
||||
#[cold]
|
||||
fn invalid_length(len: usize, exp: &Expected) -> Self {
|
||||
fn invalid_length(len: usize, exp: &dyn Expected) -> Self {
|
||||
Error::custom(format_args!("invalid length {}, expected {}", len, exp))
|
||||
}
|
||||
|
||||
@@ -403,20 +405,20 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
||||
Bool(b) => write!(formatter, "boolean `{}`", b),
|
||||
Unsigned(i) => write!(formatter, "integer `{}`", i),
|
||||
Signed(i) => write!(formatter, "integer `{}`", i),
|
||||
Float(f) => write!(formatter, "floating point `{}`", f),
|
||||
Float(f) => write!(formatter, "floating point `{}`", WithDecimalPoint(f)),
|
||||
Char(c) => write!(formatter, "character `{}`", c),
|
||||
Str(s) => write!(formatter, "string {:?}", s),
|
||||
Bytes(_) => write!(formatter, "byte array"),
|
||||
Unit => write!(formatter, "unit value"),
|
||||
Option => write!(formatter, "Option value"),
|
||||
NewtypeStruct => write!(formatter, "newtype struct"),
|
||||
Seq => write!(formatter, "sequence"),
|
||||
Map => write!(formatter, "map"),
|
||||
Enum => write!(formatter, "enum"),
|
||||
UnitVariant => write!(formatter, "unit variant"),
|
||||
NewtypeVariant => write!(formatter, "newtype variant"),
|
||||
TupleVariant => write!(formatter, "tuple variant"),
|
||||
StructVariant => write!(formatter, "struct variant"),
|
||||
Bytes(_) => formatter.write_str("byte array"),
|
||||
Unit => formatter.write_str("unit value"),
|
||||
Option => formatter.write_str("Option value"),
|
||||
NewtypeStruct => formatter.write_str("newtype struct"),
|
||||
Seq => formatter.write_str("sequence"),
|
||||
Map => formatter.write_str("map"),
|
||||
Enum => formatter.write_str("enum"),
|
||||
UnitVariant => formatter.write_str("unit variant"),
|
||||
NewtypeVariant => formatter.write_str("newtype variant"),
|
||||
TupleVariant => formatter.write_str("tuple variant"),
|
||||
StructVariant => formatter.write_str("struct variant"),
|
||||
Other(other) => formatter.write_str(other),
|
||||
}
|
||||
}
|
||||
@@ -473,6 +475,12 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
||||
/// ));
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::Expected` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Expected {
|
||||
/// Format an explanation of what data was being expected. Same signature as
|
||||
/// the `Display` and `Debug` traits.
|
||||
@@ -488,13 +496,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Expected for &'a str {
|
||||
impl Expected for &str {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for Expected + 'a {
|
||||
impl Display for dyn Expected + '_ {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
Expected::fmt(self, formatter)
|
||||
}
|
||||
@@ -533,6 +541,16 @@ impl<'a> Display for Expected + 'a {
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
// Prevents `serde_core::de::Deserialize` appearing in the error message
|
||||
// in projects with no direct dependency on serde_core.
|
||||
message = "the trait bound `{Self}: serde::Deserialize<'de>` is not satisfied",
|
||||
note = "for local types consider adding `#[derive(serde::Deserialize)]` to your `{Self}` type",
|
||||
note = "for types from other crates check whether the crate offers a `serde` feature flag",
|
||||
)
|
||||
)]
|
||||
pub trait Deserialize<'de>: Sized {
|
||||
/// Deserialize this value from the given Serde deserializer.
|
||||
///
|
||||
@@ -605,6 +623,12 @@ pub trait Deserialize<'de>: Sized {
|
||||
/// lifetimes].
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::DeserializeOwned` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
|
||||
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
||||
|
||||
@@ -770,6 +794,12 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::DeserializeSeed<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait DeserializeSeed<'de>: Sized {
|
||||
/// The type produced by using this seed.
|
||||
type Value;
|
||||
@@ -906,6 +936,12 @@ where
|
||||
/// a basic JSON `Deserializer`.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::Deserializer<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Deserializer<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -949,18 +985,15 @@ pub trait Deserializer<'de>: Sized {
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Hint that the `Deserialize` type is expecting an `i128` value.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("i128 is not supported"))
|
||||
}
|
||||
/// Hint that the `Deserialize` type is expecting an `i128` value.
|
||||
///
|
||||
/// The default behavior unconditionally returns an error.
|
||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("i128 is not supported"))
|
||||
}
|
||||
|
||||
/// Hint that the `Deserialize` type is expecting a `u8` value.
|
||||
@@ -983,18 +1016,15 @@ pub trait Deserializer<'de>: Sized {
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Hint that the `Deserialize` type is expecting an `u128` value.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("u128 is not supported"))
|
||||
}
|
||||
/// Hint that the `Deserialize` type is expecting an `u128` value.
|
||||
///
|
||||
/// The default behavior unconditionally returns an error.
|
||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("u128 is not supported"))
|
||||
}
|
||||
|
||||
/// Hint that the `Deserialize` type is expecting a `f32` value.
|
||||
@@ -1227,13 +1257,9 @@ pub trait Deserializer<'de>: Sized {
|
||||
// Not public API.
|
||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||
#[doc(hidden)]
|
||||
fn __deserialize_content<V>(
|
||||
self,
|
||||
_: crate::actually_private::T,
|
||||
visitor: V,
|
||||
) -> Result<crate::__private::de::Content<'de>, Self::Error>
|
||||
fn __deserialize_content_v1<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de, Value = crate::__private::de::Content<'de>>,
|
||||
V: Visitor<'de, Value = crate::private::Content<'de>>,
|
||||
{
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
@@ -1282,6 +1308,12 @@ pub trait Deserializer<'de>: Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::Visitor<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Visitor<'de>: Sized {
|
||||
/// The value produced by this visitor.
|
||||
type Value;
|
||||
@@ -1366,20 +1398,20 @@ pub trait Visitor<'de>: Sized {
|
||||
Err(Error::invalid_type(Unexpected::Signed(v), &self))
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
/// The input contains a `i128`.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default implementation fails with a type error.
|
||||
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let mut buf = [0u8; 58];
|
||||
let mut writer = format::Buf::new(&mut buf);
|
||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
||||
Err(Error::invalid_type(Unexpected::Other(writer.as_str()), &self))
|
||||
}
|
||||
/// The input contains a `i128`.
|
||||
///
|
||||
/// The default implementation fails with a type error.
|
||||
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let mut buf = [0u8; 58];
|
||||
let mut writer = crate::format::Buf::new(&mut buf);
|
||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
||||
Err(Error::invalid_type(
|
||||
Unexpected::Other(writer.as_str()),
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
/// The input contains a `u8`.
|
||||
@@ -1428,20 +1460,20 @@ pub trait Visitor<'de>: Sized {
|
||||
Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
/// The input contains a `u128`.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default implementation fails with a type error.
|
||||
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let mut buf = [0u8; 57];
|
||||
let mut writer = format::Buf::new(&mut buf);
|
||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
||||
Err(Error::invalid_type(Unexpected::Other(writer.as_str()), &self))
|
||||
}
|
||||
/// The input contains a `u128`.
|
||||
///
|
||||
/// The default implementation fails with a type error.
|
||||
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let mut buf = [0u8; 57];
|
||||
let mut writer = crate::format::Buf::new(&mut buf);
|
||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
||||
Err(Error::invalid_type(
|
||||
Unexpected::Other(writer.as_str()),
|
||||
&self,
|
||||
))
|
||||
}
|
||||
|
||||
/// The input contains an `f32`.
|
||||
@@ -1532,6 +1564,7 @@ pub trait Visitor<'de>: Sized {
|
||||
/// `String`.
|
||||
#[inline]
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
@@ -1590,6 +1623,7 @@ pub trait Visitor<'de>: Sized {
|
||||
/// The default implementation forwards to `visit_bytes` and then drops the
|
||||
/// `Vec<u8>`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
@@ -1706,6 +1740,12 @@ pub trait Visitor<'de>: Sized {
|
||||
/// implementation of `SeqAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::SeqAccess<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SeqAccess<'de> {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -1740,9 +1780,9 @@ pub trait SeqAccess<'de> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, A: ?Sized> SeqAccess<'de> for &'a mut A
|
||||
impl<'de, A> SeqAccess<'de> for &mut A
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
A: ?Sized + SeqAccess<'de>,
|
||||
{
|
||||
type Error = A::Error;
|
||||
|
||||
@@ -1788,6 +1828,12 @@ where
|
||||
/// implementation of `MapAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::MapAccess<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait MapAccess<'de> {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -1893,9 +1939,9 @@ pub trait MapAccess<'de> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, A: ?Sized> MapAccess<'de> for &'a mut A
|
||||
impl<'de, A> MapAccess<'de> for &mut A
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
A: ?Sized + MapAccess<'de>,
|
||||
{
|
||||
type Error = A::Error;
|
||||
|
||||
@@ -1980,6 +2026,12 @@ where
|
||||
/// implementation of `EnumAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::EnumAccess<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait EnumAccess<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -2027,6 +2079,12 @@ pub trait EnumAccess<'de>: Sized {
|
||||
/// implementation of `VariantAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::de::VariantAccess<'de>` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait VariantAccess<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization. Must match the error type of our `EnumAccess`.
|
||||
@@ -2283,10 +2341,10 @@ impl Display for OneOf {
|
||||
1 => write!(formatter, "`{}`", self.names[0]),
|
||||
2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]),
|
||||
_ => {
|
||||
tri!(write!(formatter, "one of "));
|
||||
tri!(formatter.write_str("one of "));
|
||||
for (i, alt) in self.names.iter().enumerate() {
|
||||
if i > 0 {
|
||||
tri!(write!(formatter, ", "));
|
||||
tri!(formatter.write_str(", "));
|
||||
}
|
||||
tri!(write!(formatter, "`{}`", alt));
|
||||
}
|
||||
@@ -2295,3 +2353,40 @@ impl Display for OneOf {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WithDecimalPoint(f64);
|
||||
|
||||
impl Display for WithDecimalPoint {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
struct LookForDecimalPoint<'f, 'a> {
|
||||
formatter: &'f mut fmt::Formatter<'a>,
|
||||
has_decimal_point: bool,
|
||||
}
|
||||
|
||||
impl<'f, 'a> fmt::Write for LookForDecimalPoint<'f, 'a> {
|
||||
fn write_str(&mut self, fragment: &str) -> fmt::Result {
|
||||
self.has_decimal_point |= fragment.contains('.');
|
||||
self.formatter.write_str(fragment)
|
||||
}
|
||||
|
||||
fn write_char(&mut self, ch: char) -> fmt::Result {
|
||||
self.has_decimal_point |= ch == '.';
|
||||
self.formatter.write_char(ch)
|
||||
}
|
||||
}
|
||||
|
||||
if self.0.is_finite() {
|
||||
let mut writer = LookForDecimalPoint {
|
||||
formatter,
|
||||
has_decimal_point: false,
|
||||
};
|
||||
tri!(write!(writer, "{}", self.0));
|
||||
if !writer.has_decimal_point {
|
||||
tri!(formatter.write_str(".0"));
|
||||
}
|
||||
} else {
|
||||
tri!(write!(formatter, "{}", self.0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,8 @@
|
||||
use crate::lib::*;
|
||||
|
||||
use self::private::{First, Second};
|
||||
use crate::de::{self, size_hint, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||
use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||
use crate::private::size_hint;
|
||||
use crate::ser;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -112,6 +113,7 @@ impl Debug for Error {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
&self.err
|
||||
@@ -174,6 +176,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for UnitDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Debug for UnitDeserializer<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.debug_struct("UnitDeserializer").finish()
|
||||
@@ -184,12 +197,14 @@ impl<E> Debug for UnitDeserializer<E> {
|
||||
|
||||
/// A deserializer that cannot be instantiated.
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||
pub struct NeverDeserializer<E> {
|
||||
never: !,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for !
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -222,6 +237,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for NeverDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! primitive_deserializer {
|
||||
@@ -276,6 +303,17 @@ macro_rules! primitive_deserializer {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for $name<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Debug for $name<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
@@ -292,20 +330,17 @@ primitive_deserializer!(i8, "an `i8`.", I8Deserializer, visit_i8);
|
||||
primitive_deserializer!(i16, "an `i16`.", I16Deserializer, visit_i16);
|
||||
primitive_deserializer!(i32, "an `i32`.", I32Deserializer, visit_i32);
|
||||
primitive_deserializer!(i64, "an `i64`.", I64Deserializer, visit_i64);
|
||||
primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128);
|
||||
primitive_deserializer!(isize, "an `isize`.", IsizeDeserializer, visit_i64 as i64);
|
||||
primitive_deserializer!(u8, "a `u8`.", U8Deserializer, visit_u8);
|
||||
primitive_deserializer!(u16, "a `u16`.", U16Deserializer, visit_u16);
|
||||
primitive_deserializer!(u64, "a `u64`.", U64Deserializer, visit_u64);
|
||||
primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128);
|
||||
primitive_deserializer!(usize, "a `usize`.", UsizeDeserializer, visit_u64 as u64);
|
||||
primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32);
|
||||
primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64);
|
||||
primitive_deserializer!(char, "a `char`.", CharDeserializer, visit_char);
|
||||
|
||||
serde_if_integer128! {
|
||||
primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128);
|
||||
primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128);
|
||||
}
|
||||
|
||||
/// A deserializer holding a `u32`.
|
||||
pub struct U32Deserializer<E> {
|
||||
value: u32,
|
||||
@@ -369,6 +404,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for U32Deserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::EnumAccess<'de> for U32Deserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -458,6 +504,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for StrDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -537,6 +594,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for BorrowedStrDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -565,6 +633,7 @@ impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
|
||||
|
||||
/// A deserializer holding a `String`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
pub struct StringDeserializer<E> {
|
||||
value: String,
|
||||
marker: PhantomData<E>,
|
||||
@@ -581,6 +650,7 @@ impl<E> Clone for StringDeserializer<E> {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for String
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -638,6 +708,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for StringDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> de::EnumAccess<'de> for StringDeserializer<E>
|
||||
where
|
||||
@@ -668,6 +750,7 @@ impl<E> Debug for StringDeserializer<E> {
|
||||
|
||||
/// A deserializer holding a `Cow<str>`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
pub struct CowStrDeserializer<'a, E> {
|
||||
value: Cow<'a, str>,
|
||||
marker: PhantomData<E>,
|
||||
@@ -684,6 +767,7 @@ impl<'a, E> Clone for CowStrDeserializer<'a, E> {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -744,6 +828,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for CowStrDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
|
||||
where
|
||||
@@ -821,6 +917,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for BytesDeserializer<'a, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Debug for BytesDeserializer<'a, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
@@ -869,6 +976,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for BorrowedBytesDeserializer<'de, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter
|
||||
@@ -948,6 +1066,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, I, T, E> IntoDeserializer<'de, E> for SeqDeserializer<I, E>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, I, T, E> de::SeqAccess<'de> for SeqDeserializer<I, E>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
@@ -979,7 +1110,7 @@ struct ExpectedInSeq(usize);
|
||||
impl Expected for ExpectedInSeq {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.0 == 1 {
|
||||
write!(formatter, "1 element in sequence")
|
||||
formatter.write_str("1 element in sequence")
|
||||
} else {
|
||||
write!(formatter, "{} elements in sequence", self.0)
|
||||
}
|
||||
@@ -1002,6 +1133,7 @@ where
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T>
|
||||
where
|
||||
T: IntoDeserializer<'de, E>,
|
||||
@@ -1015,6 +1147,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T>
|
||||
where
|
||||
T: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
@@ -1028,6 +1161,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
|
||||
where
|
||||
T: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
@@ -1076,6 +1210,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A> IntoDeserializer<'de, A::Error> for SeqAccessDeserializer<A>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer that iterates over a map.
|
||||
@@ -1190,6 +1335,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, I, E> IntoDeserializer<'de, E> for MapDeserializer<'de, I, E>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: private::Pair,
|
||||
First<I::Item>: IntoDeserializer<'de, E>,
|
||||
Second<I::Item>: IntoDeserializer<'de, E>,
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, I, E> de::MapAccess<'de> for MapDeserializer<'de, I, E>
|
||||
where
|
||||
I: Iterator,
|
||||
@@ -1404,7 +1564,7 @@ struct ExpectedInMap(usize);
|
||||
impl Expected for ExpectedInMap {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.0 == 1 {
|
||||
write!(formatter, "1 element in map")
|
||||
formatter.write_str("1 element in map")
|
||||
} else {
|
||||
write!(formatter, "{} elements in map", self.0)
|
||||
}
|
||||
@@ -1414,6 +1574,7 @@ impl Expected for ExpectedInMap {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V>
|
||||
where
|
||||
K: IntoDeserializer<'de, E> + Eq + Ord,
|
||||
@@ -1428,6 +1589,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
|
||||
where
|
||||
K: IntoDeserializer<'de, E> + Eq + Hash,
|
||||
@@ -1489,6 +1651,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A> IntoDeserializer<'de, A::Error> for MapAccessDeserializer<A>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
@@ -1542,6 +1715,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A> IntoDeserializer<'de, A::Error> for EnumAccessDeserializer<A>
|
||||
where
|
||||
A: de::EnumAccess<'de>,
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mod private {
|
||||
@@ -0,0 +1,121 @@
|
||||
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
|
||||
//! structures efficiently and generically.
|
||||
//!
|
||||
//! The `serde_core` crate contains Serde's trait definitions with **no support
|
||||
//! for #\[derive()\]**.
|
||||
//!
|
||||
//! In crates that derive an implementation of `Serialize` or `Deserialize`, you
|
||||
//! must depend on the [`serde`] crate, not `serde_core`.
|
||||
//!
|
||||
//! [`serde`]: https://crates.io/crates/serde
|
||||
//!
|
||||
//! In crates that handwrite implementations of Serde traits, or only use them
|
||||
//! as trait bounds, depending on `serde_core` is permitted. But `serde`
|
||||
//! re-exports all of these traits and can be used for this use case too. If in
|
||||
//! doubt, disregard `serde_core` and always use `serde`.
|
||||
//!
|
||||
//! Crates that depend on `serde_core` instead of `serde` are able to compile in
|
||||
//! parallel with `serde_derive` even when `serde`'s "derive" feature is turned on,
|
||||
//! as shown in the following build timings.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! <table>
|
||||
//! <tr><td align="center">When <code>serde_json</code> depends on <code>serde</code></td></tr>
|
||||
//! <tr><td><img src="https://github.com/user-attachments/assets/78dc179c-6ab1-4059-928c-1474b0d9d0bb"></td></tr>
|
||||
//! </table>
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! <table>
|
||||
//! <tr><td align="center">When <code>serde_json</code> depends on <code>serde_core</code></td></tr>
|
||||
//! <tr><td><img src="https://github.com/user-attachments/assets/6b6cff5e-3e45-4ac7-9db1-d99ee8b9f5f7"></td></tr>
|
||||
//! </table>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde_core/1.0.227")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// Show which crate feature enables conditionally compiled APIs in documentation.
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, rustdoc_internals))]
|
||||
#![cfg_attr(docsrs, allow(internal_features))]
|
||||
// Unstable functionality only if the user asks for it. For tracking and
|
||||
// discussion of these features please refer to this issue:
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||
// Ignored clippy and clippy_pedantic lints
|
||||
#![allow(
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
|
||||
clippy::semicolon_if_nothing_returned,
|
||||
// not available in our oldest supported compiler
|
||||
clippy::empty_enum,
|
||||
clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::cast_sign_loss,
|
||||
// things are often more readable this way
|
||||
clippy::cast_lossless,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::single_match_else,
|
||||
clippy::type_complexity,
|
||||
clippy::use_self,
|
||||
clippy::zero_prefixed_literal,
|
||||
// correctly used
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::enum_glob_use,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::incompatible_msrv,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::map_err_ignore,
|
||||
clippy::new_without_default,
|
||||
clippy::result_unit_err,
|
||||
clippy::wildcard_imports,
|
||||
// not practical
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines,
|
||||
// preference
|
||||
clippy::doc_markdown,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::unseparated_literal_suffix,
|
||||
// false positive
|
||||
clippy::needless_doctest_main,
|
||||
// noisy
|
||||
clippy::missing_errors_doc,
|
||||
clippy::must_use_candidate,
|
||||
)]
|
||||
// Restrictions
|
||||
#![deny(clippy::question_mark_used)]
|
||||
// Rustc lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
mod crate_root;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
crate_root!();
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __require_serde_not_serde_core {
|
||||
() => {
|
||||
::core::compile_error!(
|
||||
"Serde derive requires a dependency on the serde crate, not serde_core"
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Super explicit first paragraph because this shows up at the top level and
|
||||
// trips up people who are just looking for basic Serialize / Deserialize
|
||||
// documentation.
|
||||
//
|
||||
/// Helper macro when implementing the `Deserializer` part of a new data format
|
||||
/// for Serde.
|
||||
///
|
||||
@@ -104,9 +103,9 @@
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Deserializer`]: trait.Deserializer.html
|
||||
/// [`Visitor`]: de/trait.Visitor.html
|
||||
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
|
||||
/// [`Deserializer`]: crate::Deserializer
|
||||
/// [`Visitor`]: crate::de::Visitor
|
||||
/// [`Deserializer::deserialize_any`]: crate::Deserializer::deserialize_any
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! forward_to_deserialize_any {
|
||||
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
|
||||
@@ -123,7 +122,7 @@ macro_rules! forward_to_deserialize_any {
|
||||
macro_rules! forward_to_deserialize_any_method {
|
||||
($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::__private::Result<$v::Value, Self::Error>
|
||||
fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::__private::Result<$v::Value, <Self as $crate::de::Deserializer<$l>>::Error>
|
||||
where
|
||||
$v: $crate::de::Visitor<$l>,
|
||||
{
|
||||
@@ -154,9 +153,7 @@ macro_rules! forward_to_deserialize_any_helper {
|
||||
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
|
||||
};
|
||||
(i128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()}
|
||||
}
|
||||
forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()}
|
||||
};
|
||||
(u8<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
|
||||
@@ -171,9 +168,7 @@ macro_rules! forward_to_deserialize_any_helper {
|
||||
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
|
||||
};
|
||||
(u128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()}
|
||||
}
|
||||
forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()}
|
||||
};
|
||||
(f32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()}
|
||||
@@ -0,0 +1,39 @@
|
||||
use crate::lib::*;
|
||||
|
||||
// Used from generated code to buffer the contents of the Deserializer when
|
||||
// deserializing untagged enums and internally tagged enums.
|
||||
//
|
||||
// Not public API. Use serde-value instead.
|
||||
//
|
||||
// Obsoleted by format-specific buffer types (https://github.com/serde-rs/serde/pull/2912).
|
||||
#[doc(hidden)]
|
||||
pub enum Content<'de> {
|
||||
Bool(bool),
|
||||
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
|
||||
Char(char),
|
||||
String(String),
|
||||
Str(&'de str),
|
||||
ByteBuf(Vec<u8>),
|
||||
Bytes(&'de [u8]),
|
||||
|
||||
None,
|
||||
Some(Box<Content<'de>>),
|
||||
|
||||
Unit,
|
||||
Newtype(Box<Content<'de>>),
|
||||
Seq(Vec<Content<'de>>),
|
||||
Map(Vec<(Content<'de>, Content<'de>)>),
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use crate::ser;
|
||||
#[derive(Debug)]
|
||||
pub struct Error;
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl ser::Error for Error {
|
||||
fn custom<T>(_: T) -> Self
|
||||
where
|
||||
@@ -18,12 +19,14 @@ impl ser::Error for Error {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl Display for Error {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
unimplemented!()
|
||||
@@ -56,7 +59,10 @@ macro_rules! __serialize_unimplemented {
|
||||
#[macro_export]
|
||||
macro_rules! __serialize_unimplemented_method {
|
||||
($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
|
||||
fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error> {
|
||||
fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error>
|
||||
where
|
||||
$($t: ?Sized + $crate::Serialize,)*
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||
mod content;
|
||||
mod seed;
|
||||
|
||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||
#[doc(hidden)]
|
||||
pub mod doc;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod size_hint;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod string;
|
||||
|
||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||
#[doc(hidden)]
|
||||
pub use self::content::Content;
|
||||
#[doc(hidden)]
|
||||
pub use self::seed::InPlaceSeed;
|
||||
#[doc(hidden)]
|
||||
pub use crate::lib::result::Result;
|
||||
@@ -5,6 +5,7 @@ use crate::de::{Deserialize, DeserializeSeed, Deserializer};
|
||||
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
||||
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
|
||||
|
||||
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
@@ -1,3 +1,4 @@
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use crate::lib::*;
|
||||
|
||||
pub fn from_bounds<I>(iter: &I) -> Option<usize>
|
||||
@@ -0,0 +1,23 @@
|
||||
use crate::lib::*;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[doc(hidden)]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<'_, str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
|
||||
// The generated code calls this like:
|
||||
//
|
||||
// let value = &_serde::__private::from_utf8_lossy(bytes);
|
||||
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
|
||||
//
|
||||
// so it is okay for the return type to be different from the std case as long
|
||||
// as the above works.
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
#[doc(hidden)]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
// Three unicode replacement characters if it fails. They look like a
|
||||
// white-on-black question mark. The user will recognize it as invalid
|
||||
// UTF-8.
|
||||
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
|
||||
}
|
||||
@@ -35,7 +35,7 @@ macro_rules! fmt_primitives {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
impl<'a> Serializer for &mut fmt::Formatter<'a> {
|
||||
type Ok = ();
|
||||
type Error = fmt::Error;
|
||||
type SerializeSeq = Impossible<(), fmt::Error>;
|
||||
@@ -52,10 +52,12 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
serialize_i16: i16,
|
||||
serialize_i32: i32,
|
||||
serialize_i64: i64,
|
||||
serialize_i128: i128,
|
||||
serialize_u8: u8,
|
||||
serialize_u16: u16,
|
||||
serialize_u32: u32,
|
||||
serialize_u64: u64,
|
||||
serialize_u128: u128,
|
||||
serialize_f32: f32,
|
||||
serialize_f64: f64,
|
||||
serialize_char: char,
|
||||
@@ -63,13 +65,6 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
serialize_unit_struct: &'static str,
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
fmt_primitives! {
|
||||
serialize_i128: i128,
|
||||
serialize_u128: u128,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
@@ -79,9 +74,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
Display::fmt(variant, self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> fmt::Result
|
||||
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Serialize::serialize(value, self)
|
||||
}
|
||||
@@ -94,9 +89,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> fmt::Result
|
||||
fn serialize_some<T>(self, _value: &T) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Err(fmt::Error)
|
||||
}
|
||||
@@ -105,7 +100,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
@@ -113,7 +108,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
_value: &T,
|
||||
) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
Err(fmt::Error)
|
||||
}
|
||||
@@ -166,9 +161,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> fmt::Result
|
||||
fn collect_str<T>(self, value: &T) -> fmt::Result
|
||||
where
|
||||
T: Display,
|
||||
T: ?Sized + Display,
|
||||
{
|
||||
Display::fmt(value, self)
|
||||
}
|
||||
@@ -24,20 +24,17 @@ primitive_impl!(i8, serialize_i8);
|
||||
primitive_impl!(i16, serialize_i16);
|
||||
primitive_impl!(i32, serialize_i32);
|
||||
primitive_impl!(i64, serialize_i64);
|
||||
primitive_impl!(i128, serialize_i128);
|
||||
primitive_impl!(usize, serialize_u64 as u64);
|
||||
primitive_impl!(u8, serialize_u8);
|
||||
primitive_impl!(u16, serialize_u16);
|
||||
primitive_impl!(u32, serialize_u32);
|
||||
primitive_impl!(u64, serialize_u64);
|
||||
primitive_impl!(u128, serialize_u128);
|
||||
primitive_impl!(f32, serialize_f32);
|
||||
primitive_impl!(f64, serialize_f64);
|
||||
primitive_impl!(char, serialize_char);
|
||||
|
||||
serde_if_integer128! {
|
||||
primitive_impl!(i128, serialize_i128);
|
||||
primitive_impl!(u128, serialize_u128);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl Serialize for str {
|
||||
@@ -51,6 +48,7 @@ impl Serialize for str {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl Serialize for String {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -73,6 +71,7 @@ impl<'a> Serialize for fmt::Arguments<'a> {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", not(no_core_cstr)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl Serialize for CStr {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -84,6 +83,7 @@ impl Serialize for CStr {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
impl Serialize for CString {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -114,7 +114,10 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl<T: ?Sized> Serialize for PhantomData<T> {
|
||||
impl<T> Serialize for PhantomData<T>
|
||||
where
|
||||
T: ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -182,9 +185,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "std", feature = "alloc"), not(no_relaxed_trait_bounds)))]
|
||||
macro_rules! seq_impl {
|
||||
($ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>) => {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$ty:ident <T $(, $typaram:ident : $bound:ident)*>
|
||||
) => {
|
||||
$(#[$attr])*
|
||||
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
||||
where
|
||||
T: Serialize,
|
||||
@@ -200,42 +206,41 @@ macro_rules! seq_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "std", feature = "alloc"), no_relaxed_trait_bounds))]
|
||||
macro_rules! seq_impl {
|
||||
($ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>) => {
|
||||
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
||||
where
|
||||
T: Serialize $(+ $tbound1 $(+ $tbound2)*)*,
|
||||
$($typaram: $bound,)*
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_seq(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
seq_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
BinaryHeap<T>
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(BinaryHeap<T: Ord>);
|
||||
seq_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
BTreeSet<T>
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(BTreeSet<T: Ord>);
|
||||
seq_impl! {
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
HashSet<T, H: BuildHasher>
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>);
|
||||
seq_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
LinkedList<T>
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(LinkedList<T>);
|
||||
seq_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
Vec<T>
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(Vec<T>);
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
seq_impl!(VecDeque<T>);
|
||||
seq_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
VecDeque<T>
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -342,6 +347,7 @@ impl Serialize for () {
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||
impl Serialize for ! {
|
||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -356,28 +362,46 @@ impl Serialize for ! {
|
||||
macro_rules! tuple_impls {
|
||||
($($len:expr => ($($n:tt $name:ident)+))+) => {
|
||||
$(
|
||||
#[cfg_attr(docsrs, doc(hidden))]
|
||||
impl<$($name),+> Serialize for ($($name,)+)
|
||||
where
|
||||
$($name: Serialize,)+
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tuple = tri!(serializer.serialize_tuple($len));
|
||||
$(
|
||||
tri!(tuple.serialize_element(&self.$n));
|
||||
)+
|
||||
tuple.end()
|
||||
}
|
||||
tuple_impl_body!($len => ($($n)+));
|
||||
}
|
||||
)+
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! tuple_impl_body {
|
||||
($len:expr => ($($n:tt)+)) => {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut tuple = tri!(serializer.serialize_tuple($len));
|
||||
$(
|
||||
tri!(tuple.serialize_element(&self.$n));
|
||||
)+
|
||||
tuple.end()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg_attr(docsrs, doc(fake_variadic))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc = "This trait is implemented for tuples up to 16 items long."
|
||||
)]
|
||||
impl<T> Serialize for (T,)
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
tuple_impl_body!(1 => (0));
|
||||
}
|
||||
|
||||
tuple_impls! {
|
||||
1 => (0 T0)
|
||||
2 => (0 T0 1 T1)
|
||||
3 => (0 T0 1 T1 2 T2)
|
||||
4 => (0 T0 1 T1 2 T2 3 T3)
|
||||
@@ -397,9 +421,12 @@ tuple_impls! {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(all(any(feature = "std", feature = "alloc"), not(no_relaxed_trait_bounds)))]
|
||||
macro_rules! map_impl {
|
||||
($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)*>) => {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)*>
|
||||
) => {
|
||||
$(#[$attr])*
|
||||
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
|
||||
where
|
||||
K: Serialize,
|
||||
@@ -416,40 +443,26 @@ macro_rules! map_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "std", feature = "alloc"), no_relaxed_trait_bounds))]
|
||||
macro_rules! map_impl {
|
||||
($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)*>) => {
|
||||
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
|
||||
where
|
||||
K: Serialize $(+ $kbound1 $(+ $kbound2)*)*,
|
||||
V: Serialize,
|
||||
$($typaram: $bound,)*
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_map(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
map_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
BTreeMap<K: Ord, V>
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
map_impl!(BTreeMap<K: Ord, V>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
|
||||
map_impl! {
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
HashMap<K: Eq + Hash, V, H: BuildHasher>
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! deref_impl {
|
||||
(
|
||||
$(#[doc = $doc:tt])*
|
||||
$(#[$attr:meta])*
|
||||
<$($desc:tt)+
|
||||
) => {
|
||||
$(#[doc = $doc])*
|
||||
$(#[$attr])*
|
||||
impl <$($desc)+ {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -462,13 +475,20 @@ macro_rules! deref_impl {
|
||||
};
|
||||
}
|
||||
|
||||
deref_impl!(<'a, T: ?Sized> Serialize for &'a T where T: Serialize);
|
||||
deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize);
|
||||
deref_impl! {
|
||||
<'a, T> Serialize for &'a T where T: ?Sized + Serialize
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize);
|
||||
deref_impl! {
|
||||
<'a, T> Serialize for &'a mut T where T: ?Sized + Serialize
|
||||
}
|
||||
|
||||
deref_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
<T> Serialize for Box<T> where T: ?Sized + Serialize
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl! {
|
||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||
///
|
||||
@@ -478,10 +498,11 @@ deref_impl! {
|
||||
/// repeated data.
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
<T: ?Sized> Serialize for Rc<T> where T: Serialize
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
|
||||
<T> Serialize for Rc<T> where T: ?Sized + Serialize
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
deref_impl! {
|
||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||
///
|
||||
@@ -491,11 +512,16 @@ deref_impl! {
|
||||
/// repeated data.
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
<T: ?Sized> Serialize for Arc<T> where T: Serialize
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))))]
|
||||
<T> Serialize for Arc<T> where T: ?Sized + Serialize
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
|
||||
deref_impl! {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||
<'a, T> Serialize for Cow<'a, T> where T: ?Sized + Serialize + ToOwned
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -503,9 +529,13 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<T: ?Sized> Serialize for RcWeak<T>
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
|
||||
)]
|
||||
impl<T> Serialize for RcWeak<T>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -519,9 +549,13 @@ where
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<T: ?Sized> Serialize for ArcWeak<T>
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(all(feature = "rc", any(feature = "std", feature = "alloc"))))
|
||||
)]
|
||||
impl<T> Serialize for ArcWeak<T>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -548,34 +582,19 @@ macro_rules! nonzero_integers {
|
||||
}
|
||||
}
|
||||
|
||||
nonzero_integers! {
|
||||
NonZeroU8,
|
||||
NonZeroU16,
|
||||
NonZeroU32,
|
||||
NonZeroU64,
|
||||
NonZeroUsize,
|
||||
}
|
||||
|
||||
#[cfg(not(no_num_nonzero_signed))]
|
||||
nonzero_integers! {
|
||||
NonZeroI8,
|
||||
NonZeroI16,
|
||||
NonZeroI32,
|
||||
NonZeroI64,
|
||||
NonZeroI128,
|
||||
NonZeroIsize,
|
||||
}
|
||||
|
||||
// Currently 128-bit integers do not work on Emscripten targets so we need an
|
||||
// additional `#[cfg]`
|
||||
serde_if_integer128! {
|
||||
nonzero_integers! {
|
||||
NonZeroU128,
|
||||
}
|
||||
|
||||
#[cfg(not(no_num_nonzero_signed))]
|
||||
nonzero_integers! {
|
||||
NonZeroI128,
|
||||
}
|
||||
NonZeroU8,
|
||||
NonZeroU16,
|
||||
NonZeroU32,
|
||||
NonZeroU64,
|
||||
NonZeroU128,
|
||||
NonZeroUsize,
|
||||
}
|
||||
|
||||
impl<T> Serialize for Cell<T>
|
||||
@@ -590,9 +609,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Serialize for RefCell<T>
|
||||
impl<T> Serialize for RefCell<T>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -606,9 +625,10 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: ?Sized> Serialize for Mutex<T>
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl<T> Serialize for Mutex<T>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -622,9 +642,10 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: ?Sized> Serialize for RwLock<T>
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl<T> Serialize for RwLock<T>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -639,6 +660,8 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "result")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "result")))]
|
||||
impl<T, E> Serialize for Result<T, E>
|
||||
where
|
||||
T: Serialize,
|
||||
@@ -675,6 +698,7 @@ impl Serialize for Duration {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl Serialize for SystemTime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -698,27 +722,17 @@ impl Serialize for SystemTime {
|
||||
/// statically known to never have more than a constant `MAX_LEN` bytes.
|
||||
///
|
||||
/// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes.
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
macro_rules! serialize_display_bounded_length {
|
||||
($value:expr, $max:expr, $serializer:expr) => {{
|
||||
let mut buffer = [0u8; $max];
|
||||
let remaining_len = {
|
||||
let mut remaining = &mut buffer[..];
|
||||
write!(remaining, "{}", $value).unwrap();
|
||||
remaining.len()
|
||||
};
|
||||
let written_len = buffer.len() - remaining_len;
|
||||
let written = &buffer[..written_len];
|
||||
|
||||
// write! only provides fmt::Formatter to Display implementations, which
|
||||
// has methods write_str and write_char but no method to write arbitrary
|
||||
// bytes. Therefore `written` must be valid UTF-8.
|
||||
let written_str = str::from_utf8(written).expect("must be valid UTF-8");
|
||||
$serializer.serialize_str(written_str)
|
||||
let mut writer = crate::format::Buf::new(&mut buffer);
|
||||
write!(&mut writer, "{}", $value).unwrap();
|
||||
$serializer.serialize_str(writer.as_str())
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::IpAddr {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -742,7 +756,7 @@ impl Serialize for net::IpAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
const DEC_DIGITS_LUT: &[u8] = b"\
|
||||
0001020304050607080910111213141516171819\
|
||||
2021222324252627282930313233343536373839\
|
||||
@@ -750,7 +764,7 @@ const DEC_DIGITS_LUT: &[u8] = b"\
|
||||
6061626364656667686970717273747576777879\
|
||||
8081828384858687888990919293949596979899";
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
#[inline]
|
||||
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
||||
if n >= 100 {
|
||||
@@ -771,7 +785,7 @@ fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
#[test]
|
||||
fn test_format_u8() {
|
||||
let mut i = 0u8;
|
||||
@@ -788,7 +802,7 @@ fn test_format_u8() {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::Ipv4Addr {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -812,7 +826,7 @@ impl Serialize for net::Ipv4Addr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::Ipv6Addr {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -828,7 +842,7 @@ impl Serialize for net::Ipv6Addr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::SocketAddr {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -852,7 +866,7 @@ impl Serialize for net::SocketAddr {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::SocketAddrV4 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -868,7 +882,7 @@ impl Serialize for net::SocketAddrV4 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||
impl Serialize for net::SocketAddrV6 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -890,6 +904,7 @@ impl Serialize for net::SocketAddrV6 {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl Serialize for Path {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -903,6 +918,7 @@ impl Serialize for Path {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||
impl Serialize for PathBuf {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -913,6 +929,7 @@ impl Serialize for PathBuf {
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
|
||||
impl Serialize for OsStr {
|
||||
#[cfg(unix)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -935,6 +952,7 @@ impl Serialize for OsStr {
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
|
||||
impl Serialize for OsString {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -959,6 +977,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(no_core_num_saturating))]
|
||||
impl<T> Serialize for Saturating<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Reverse<T>
|
||||
where
|
||||
T: Serialize,
|
||||
@@ -979,6 +1011,7 @@ macro_rules! atomic_impl {
|
||||
($($ty:ident $size:expr)*) => {
|
||||
$(
|
||||
#[cfg(any(no_target_has_atomic, target_has_atomic = $size))]
|
||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
|
||||
impl Serialize for $ty {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -17,7 +17,7 @@ use crate::ser::{
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::ser::{Serializer, Impossible};
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// # use serde_core::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
@@ -41,7 +41,7 @@ use crate::ser::{
|
||||
/// }
|
||||
///
|
||||
/// /* other Serializer methods */
|
||||
/// # serde::__serialize_unimplemented! {
|
||||
/// # serde_core::__serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant
|
||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||
@@ -49,14 +49,14 @@ use crate::ser::{
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Serializer`]: trait.Serializer.html
|
||||
/// [`SerializeSeq`]: trait.SerializeSeq.html
|
||||
/// [`SerializeTuple`]: trait.SerializeTuple.html
|
||||
/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html
|
||||
/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html
|
||||
/// [`SerializeMap`]: trait.SerializeMap.html
|
||||
/// [`SerializeStruct`]: trait.SerializeStruct.html
|
||||
/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html
|
||||
/// [`Serializer`]: crate::Serializer
|
||||
/// [`SerializeSeq`]: crate::ser::SerializeSeq
|
||||
/// [`SerializeTuple`]: crate::ser::SerializeTuple
|
||||
/// [`SerializeTupleStruct`]: crate::ser::SerializeTupleStruct
|
||||
/// [`SerializeTupleVariant`]: crate::ser::SerializeTupleVariant
|
||||
/// [`SerializeMap`]: crate::ser::SerializeMap
|
||||
/// [`SerializeStruct`]: crate::ser::SerializeStruct
|
||||
/// [`SerializeStructVariant`]: crate::ser::SerializeStructVariant
|
||||
pub struct Impossible<Ok, Error> {
|
||||
void: Void,
|
||||
ok: PhantomData<Ok>,
|
||||
@@ -72,9 +72,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
@@ -92,9 +92,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
@@ -112,9 +112,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
@@ -132,9 +132,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
@@ -152,17 +152,17 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error>
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
@@ -180,9 +180,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
@@ -201,9 +201,9 @@ where
|
||||
type Ok = Ok;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
T: ?Sized + Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
@@ -61,8 +61,8 @@
|
||||
//! - RefCell\<T\>
|
||||
//! - Mutex\<T\>
|
||||
//! - RwLock\<T\>
|
||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Rc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - **Collection types**:
|
||||
//! - BTreeMap\<K, V\>
|
||||
//! - BTreeSet\<T\>
|
||||
@@ -97,8 +97,8 @@
|
||||
//!
|
||||
//! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html
|
||||
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
|
||||
//! [`Serialize`]: ../trait.Serialize.html
|
||||
//! [`Serializer`]: ../trait.Serializer.html
|
||||
//! [`Serialize`]: crate::Serialize
|
||||
//! [`Serializer`]: crate::Serializer
|
||||
//! [`postcard`]: https://github.com/jamesmunns/postcard
|
||||
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
||||
//! [`serde_derive`]: https://crates.io/crates/serde_derive
|
||||
@@ -115,10 +115,10 @@ mod impossible;
|
||||
|
||||
pub use self::impossible::Impossible;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
||||
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::std_error::Error as StdError;
|
||||
#[cfg(all(feature = "unstable", not(feature = "std")))]
|
||||
#[cfg(not(any(feature = "std", no_core_error)))]
|
||||
#[doc(no_inline)]
|
||||
pub use core::error::Error as StdError;
|
||||
#[cfg(feature = "std")]
|
||||
@@ -139,6 +139,12 @@ macro_rules! declare_error_trait {
|
||||
/// type appropriate for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::Error` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Error: Sized $(+ $($supertrait)::+)* {
|
||||
/// Used when a [`Serialize`] implementation encounters any error
|
||||
/// while serializing a type.
|
||||
@@ -173,8 +179,8 @@ macro_rules! declare_error_trait {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
|
||||
/// [`Serialize`]: ../trait.Serialize.html
|
||||
/// [`Path`]: std::path::Path
|
||||
/// [`Serialize`]: crate::Serialize
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display;
|
||||
@@ -215,6 +221,16 @@ declare_error_trait!(Error: Sized + Debug + Display);
|
||||
/// [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
||||
/// [`serde_derive`]: https://crates.io/crates/serde_derive
|
||||
/// [derive section of the manual]: https://serde.rs/derive.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
// Prevents `serde_core::ser::Serialize` appearing in the error message
|
||||
// in projects with no direct dependency on serde_core.
|
||||
message = "the trait bound `{Self}: serde::Serialize` is not satisfied",
|
||||
note = "for local types consider adding `#[derive(serde::Serialize)]` to your `{Self}` type",
|
||||
note = "for types from other crates check whether the crate offers a `serde` feature flag",
|
||||
)
|
||||
)]
|
||||
pub trait Serialize {
|
||||
/// Serialize this value into the given Serde serializer.
|
||||
///
|
||||
@@ -330,6 +346,12 @@ pub trait Serialize {
|
||||
/// a basic JSON `Serializer`.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::Serializer` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait Serializer: Sized {
|
||||
/// The output type produced by this `Serializer` during successful
|
||||
/// serialization. Most serializers that produce text or binary output
|
||||
@@ -338,7 +360,7 @@ pub trait Serializer: Sized {
|
||||
/// in-memory data structures may be simplified by using `Ok` to propagate
|
||||
/// the data structure around.
|
||||
///
|
||||
/// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
/// [`io::Write`]: std::io::Write
|
||||
type Ok;
|
||||
|
||||
/// The error type when some error occurs during serialization.
|
||||
@@ -391,7 +413,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for bool {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -413,7 +435,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i8 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -435,7 +457,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i16 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -457,7 +479,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i32 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -475,7 +497,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i64 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -488,30 +510,27 @@ pub trait Serializer: Sized {
|
||||
/// ```
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Serialize an `i128` value.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i128 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// serializer.serialize_i128(*self)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
let _ = v;
|
||||
Err(Error::custom("i128 is not supported"))
|
||||
}
|
||||
/// Serialize an `i128` value.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for i128 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// serializer.serialize_i128(*self)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default behavior unconditionally returns an error.
|
||||
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
let _ = v;
|
||||
Err(Error::custom("i128 is not supported"))
|
||||
}
|
||||
|
||||
/// Serialize a `u8` value.
|
||||
@@ -523,7 +542,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u8 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -545,7 +564,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u16 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -567,7 +586,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u32 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -585,7 +604,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u64 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -598,30 +617,27 @@ pub trait Serializer: Sized {
|
||||
/// ```
|
||||
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Serialize a `u128` value.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u128 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// serializer.serialize_u128(*self)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
let _ = v;
|
||||
Err(Error::custom("u128 is not supported"))
|
||||
}
|
||||
/// Serialize a `u128` value.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for u128 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// serializer.serialize_u128(*self)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The default behavior unconditionally returns an error.
|
||||
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
let _ = v;
|
||||
Err(Error::custom("u128 is not supported"))
|
||||
}
|
||||
|
||||
/// Serialize an `f32` value.
|
||||
@@ -633,7 +649,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for f32 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -651,7 +667,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for f64 {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -672,7 +688,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for char {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -690,7 +706,7 @@ pub trait Serializer: Sized {
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for str {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -713,7 +729,7 @@ pub trait Serializer: Sized {
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::ser::{Serializer, SerializeSeq};
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// # use serde_core::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
@@ -729,7 +745,7 @@ pub trait Serializer: Sized {
|
||||
/// seq.end()
|
||||
/// }
|
||||
/// #
|
||||
/// # serde::__serialize_unimplemented! {
|
||||
/// # serde_core::__serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant
|
||||
/// # seq tuple tuple_struct tuple_variant map struct struct_variant
|
||||
@@ -768,7 +784,7 @@ pub trait Serializer: Sized {
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None
|
||||
/// [`None`]: core::option::Option::None
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error>;
|
||||
|
||||
/// Serialize a [`Some(T)`] value.
|
||||
@@ -801,17 +817,17 @@ pub trait Serializer: Sized {
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`Some(T)`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
/// [`Some(T)`]: core::option::Option::Some
|
||||
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Serialize a `()` value.
|
||||
///
|
||||
/// ```edition2021
|
||||
/// # use serde::Serializer;
|
||||
/// #
|
||||
/// # serde::__private_serialize!();
|
||||
/// # serde_core::__private_serialize!();
|
||||
/// #
|
||||
/// impl Serialize for () {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -897,13 +913,13 @@ pub trait Serializer: Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
fn serialize_newtype_struct<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`.
|
||||
///
|
||||
@@ -931,7 +947,7 @@ pub trait Serializer: Sized {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
fn serialize_newtype_variant<T>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
@@ -939,7 +955,7 @@ pub trait Serializer: Sized {
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Begin to serialize a variably sized sequence. This call must be
|
||||
/// followed by zero or more calls to `serialize_element`, then a call to
|
||||
@@ -1176,7 +1192,8 @@ pub trait Serializer: Sized {
|
||||
/// then a call to `end`.
|
||||
///
|
||||
/// The `name` is the name of the struct and the `len` is the number of
|
||||
/// data fields that will be serialized.
|
||||
/// data fields that will be serialized. `len` does not include fields
|
||||
/// which are skipped with [`SerializeStruct::skip_field`].
|
||||
///
|
||||
/// ```edition2021
|
||||
/// use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
@@ -1213,6 +1230,8 @@ pub trait Serializer: Sized {
|
||||
/// The `name` is the name of the enum, the `variant_index` is the index of
|
||||
/// this variant within the enum, the `variant` is the name of the variant,
|
||||
/// and the `len` is the number of data fields that will be serialized.
|
||||
/// `len` does not include fields which are skipped with
|
||||
/// [`SerializeStructVariant::skip_field`].
|
||||
///
|
||||
/// ```edition2021
|
||||
/// use serde::ser::{Serialize, SerializeStructVariant, Serializer};
|
||||
@@ -1349,12 +1368,11 @@ pub trait Serializer: Sized {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
|
||||
/// [`serialize_str`]: #tymethod.serialize_str
|
||||
/// [`serialize_str`]: Self::serialize_str
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display,
|
||||
T: ?Sized + Display,
|
||||
{
|
||||
self.serialize_str(&value.to_string())
|
||||
}
|
||||
@@ -1385,9 +1403,9 @@ pub trait Serializer: Sized {
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display;
|
||||
T: ?Sized + Display;
|
||||
|
||||
/// Determine whether `Serialize` implementations should serialize in
|
||||
/// human-readable form.
|
||||
@@ -1491,6 +1509,12 @@ pub trait Serializer: Sized {
|
||||
/// implementation of `SerializeSeq` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeSeq` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeSeq {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1499,9 +1523,9 @@ pub trait SerializeSeq {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a sequence element.
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Finish serializing a sequence.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
@@ -1591,6 +1615,12 @@ pub trait SerializeSeq {
|
||||
/// implementation of `SerializeTuple` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeTuple` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeTuple {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1599,9 +1629,9 @@ pub trait SerializeTuple {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a tuple element.
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Finish serializing a tuple.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
@@ -1636,6 +1666,12 @@ pub trait SerializeTuple {
|
||||
/// implementation of `SerializeTupleStruct` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeTupleStruct` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeTupleStruct {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1644,9 +1680,9 @@ pub trait SerializeTupleStruct {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a tuple struct field.
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Finish serializing a tuple struct.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
@@ -1694,6 +1730,12 @@ pub trait SerializeTupleStruct {
|
||||
/// implementation of `SerializeTupleVariant` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeTupleVariant` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeTupleVariant {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1702,9 +1744,9 @@ pub trait SerializeTupleVariant {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a tuple variant field.
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Finish serializing a tuple variant.
|
||||
fn end(self) -> Result<Self::Ok, Self::Error>;
|
||||
@@ -1760,6 +1802,12 @@ pub trait SerializeTupleVariant {
|
||||
/// implementation of `SerializeMap` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeMap` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeMap {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1773,9 +1821,9 @@ pub trait SerializeMap {
|
||||
/// `serialize_entry` instead as it may be implemented more efficiently in
|
||||
/// some formats compared to a pair of calls to `serialize_key` and
|
||||
/// `serialize_value`.
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Serialize a map value.
|
||||
///
|
||||
@@ -1783,9 +1831,9 @@ pub trait SerializeMap {
|
||||
///
|
||||
/// Calling `serialize_value` before `serialize_key` is incorrect and is
|
||||
/// allowed to panic or produce bogus results.
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Serialize a map entry consisting of a key and a value.
|
||||
///
|
||||
@@ -1801,17 +1849,13 @@ pub trait SerializeMap {
|
||||
/// care about performance or are not able to optimize `serialize_entry` any
|
||||
/// better than this.
|
||||
///
|
||||
/// [`Serialize`]: ../trait.Serialize.html
|
||||
/// [`serialize_key`]: #tymethod.serialize_key
|
||||
/// [`serialize_value`]: #tymethod.serialize_value
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
||||
&mut self,
|
||||
key: &K,
|
||||
value: &V,
|
||||
) -> Result<(), Self::Error>
|
||||
/// [`Serialize`]: crate::Serialize
|
||||
/// [`serialize_key`]: Self::serialize_key
|
||||
/// [`serialize_value`]: Self::serialize_value
|
||||
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
|
||||
where
|
||||
K: Serialize,
|
||||
V: Serialize,
|
||||
K: ?Sized + Serialize,
|
||||
V: ?Sized + Serialize,
|
||||
{
|
||||
tri!(self.serialize_key(key));
|
||||
self.serialize_value(value)
|
||||
@@ -1854,6 +1898,12 @@ pub trait SerializeMap {
|
||||
/// implementation of `SerializeStruct` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeStruct` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeStruct {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1862,15 +1912,13 @@ pub trait SerializeStruct {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a struct field.
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Indicate that a struct field has been skipped.
|
||||
///
|
||||
/// The default implementation does nothing.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
@@ -1920,6 +1968,12 @@ pub trait SerializeStruct {
|
||||
/// implementation of `SerializeStructVariant` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
#[cfg_attr(
|
||||
not(no_diagnostic_namespace),
|
||||
diagnostic::on_unimplemented(
|
||||
message = "the trait bound `{Self}: serde::ser::SerializeStructVariant` is not satisfied",
|
||||
)
|
||||
)]
|
||||
pub trait SerializeStructVariant {
|
||||
/// Must match the `Ok` type of our `Serializer`.
|
||||
type Ok;
|
||||
@@ -1928,15 +1982,13 @@ pub trait SerializeStructVariant {
|
||||
type Error: Error;
|
||||
|
||||
/// Serialize a struct variant field.
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize;
|
||||
T: ?Sized + Serialize;
|
||||
|
||||
/// Indicate that a struct variant field has been skipped.
|
||||
///
|
||||
/// The default implementation does nothing.
|
||||
#[inline]
|
||||
fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> {
|
||||
let _ = key;
|
||||
@@ -42,7 +42,7 @@ use crate::lib::{Debug, Display};
|
||||
/// ```
|
||||
pub trait Error: Debug + Display {
|
||||
/// The underlying cause of this error, if any.
|
||||
fn source(&self) -> Option<&(Error + 'static)> {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
+15
-6
@@ -1,16 +1,18 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.186" # remember to update html_root_url
|
||||
version = "1.0.227"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
categories = ["no-std", "no-std::no-alloc"]
|
||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||
documentation = "https://serde.rs/derive.html"
|
||||
edition = "2021"
|
||||
exclude = ["build.rs"]
|
||||
homepage = "https://serde.rs"
|
||||
keywords = ["serde", "serialization", "no_std", "derive"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "crates-io.md"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.61"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
@@ -21,13 +23,20 @@ name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = "2.0.28"
|
||||
proc-macro2 = { workspace = true, features = ["proc-macro"] }
|
||||
quote = { workspace = true, features = ["proc-macro"] }
|
||||
syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1", path = "../serde" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
// Warning: build.rs is not published to crates.io.
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rustc-cfg=check_cfg");
|
||||
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
|
||||
println!("cargo:rustc-check-cfg=cfg(exhaustive)");
|
||||
}
|
||||
@@ -144,6 +144,7 @@ pub fn with_bound(
|
||||
|
||||
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
||||
match ty {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::BareFn(ty) => {
|
||||
for arg in &ty.inputs {
|
||||
@@ -181,7 +182,6 @@ pub fn with_bound(
|
||||
|
||||
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -196,16 +196,13 @@ pub fn with_bound(
|
||||
syn::PathArguments::AngleBracketed(arguments) => {
|
||||
for arg in &arguments.args {
|
||||
match arg {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
||||
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
|
||||
syn::GenericArgument::Lifetime(_)
|
||||
| syn::GenericArgument::Const(_)
|
||||
| syn::GenericArgument::AssocConst(_)
|
||||
| syn::GenericArgument::Constraint(_) => {}
|
||||
#[cfg_attr(
|
||||
all(test, exhaustive),
|
||||
deny(non_exhaustive_omitted_patterns)
|
||||
)]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -228,9 +225,11 @@ pub fn with_bound(
|
||||
|
||||
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
||||
match bound {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
||||
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
syn::TypeParamBound::Lifetime(_)
|
||||
| syn::TypeParamBound::PreciseCapture(_)
|
||||
| syn::TypeParamBound::Verbatim(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
+138
-2301
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
use crate::de::enum_adjacently;
|
||||
use crate::de::enum_externally;
|
||||
use crate::de::enum_internally;
|
||||
use crate::de::enum_untagged;
|
||||
use crate::de::identifier;
|
||||
use crate::de::{field_i, FieldWithAliases, Parameters};
|
||||
use crate::fragment::{Expr, Fragment, Stmts};
|
||||
use crate::internals::ast::Variant;
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}`
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
// The variants have already been checked (in ast.rs) that all untagged variants appear at the end
|
||||
match variants.iter().position(|var| var.attrs.untagged()) {
|
||||
Some(variant_idx) => {
|
||||
let (tagged, untagged) = variants.split_at(variant_idx);
|
||||
let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
|
||||
// Ignore any error associated with non-untagged deserialization so that we
|
||||
// can fall through to the untagged variants. This may be infallible so we
|
||||
// need to provide the error type.
|
||||
let first_attempt = quote! {
|
||||
if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() {
|
||||
return _serde::#private::Ok(__ok);
|
||||
}
|
||||
};
|
||||
enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt))
|
||||
}
|
||||
None => deserialize_homogeneous_enum(params, variants, cattrs),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_homogeneous_enum(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
match cattrs.tag() {
|
||||
attr::TagType::External => enum_externally::deserialize(params, variants, cattrs),
|
||||
attr::TagType::Internal { tag } => {
|
||||
enum_internally::deserialize(params, variants, cattrs, tag)
|
||||
}
|
||||
attr::TagType::Adjacent { tag, content } => {
|
||||
enum_adjacently::deserialize(params, variants, cattrs, tag, content)
|
||||
}
|
||||
attr::TagType::None => enum_untagged::deserialize(params, variants, cattrs, None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
|
||||
let deserialized_variants = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_i, variant)| !variant.attrs.skip_deserializing());
|
||||
|
||||
let fallthrough = deserialized_variants
|
||||
.clone()
|
||||
.find(|(_i, variant)| variant.attrs.other())
|
||||
.map(|(i, _variant)| {
|
||||
let ignore_variant = field_i(i);
|
||||
quote!(_serde::#private::Ok(__Field::#ignore_variant))
|
||||
});
|
||||
|
||||
let variants_stmt = {
|
||||
let variant_names = deserialized_variants
|
||||
.clone()
|
||||
.flat_map(|(_i, variant)| variant.attrs.aliases());
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
|
||||
}
|
||||
};
|
||||
|
||||
let deserialized_variants: Vec<_> = deserialized_variants
|
||||
.map(|(i, variant)| FieldWithAliases {
|
||||
ident: field_i(i),
|
||||
aliases: variant.attrs.aliases(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let variant_visitor = Stmts(identifier::deserialize_generated(
|
||||
&deserialized_variants,
|
||||
false, // variant identifiers do not depend on the presence of flatten fields
|
||||
true,
|
||||
None,
|
||||
fallthrough,
|
||||
));
|
||||
|
||||
(variants_stmt, variant_visitor)
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
//! Deserialization for adjacently tagged enums:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! #[serde(tag = "...", content = "...")]
|
||||
//! enum Enum {}
|
||||
//! ```
|
||||
|
||||
use crate::de::enum_;
|
||||
use crate::de::enum_untagged;
|
||||
use crate::de::{field_i, Parameters};
|
||||
use crate::fragment::{Fragment, Match};
|
||||
use crate::internals::ast::{Style, Variant};
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
tag: &str,
|
||||
content: &str,
|
||||
) -> Fragment {
|
||||
let this_type = ¶ms.this_type;
|
||||
let this_value = ¶ms.this_value;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
|
||||
|
||||
let variant_arms: &Vec<_> = &variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||
.map(|(i, variant)| {
|
||||
let variant_index = field_i(i);
|
||||
|
||||
let block = Match(enum_untagged::deserialize_variant(params, variant, cattrs));
|
||||
|
||||
quote! {
|
||||
__Field::#variant_index => #block
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let rust_name = params.type_name();
|
||||
let expecting = format!("adjacently tagged enum {}", rust_name);
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let deny_unknown_fields = cattrs.deny_unknown_fields();
|
||||
|
||||
// If unknown fields are allowed, we pick the visitor that can step over
|
||||
// those. Otherwise we pick the visitor that fails on unknown keys.
|
||||
let field_visitor_ty = if deny_unknown_fields {
|
||||
quote! { _serde::#private::de::TagOrContentFieldVisitor }
|
||||
} else {
|
||||
quote! { _serde::#private::de::TagContentOtherFieldVisitor }
|
||||
};
|
||||
|
||||
let mut missing_content = quote! {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
|
||||
};
|
||||
let mut missing_content_fallthrough = quote!();
|
||||
let missing_content_arms = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||
.filter_map(|(i, variant)| {
|
||||
let variant_index = field_i(i);
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
let arm = match variant.style {
|
||||
Style::Unit => quote! {
|
||||
_serde::#private::Ok(#this_value::#variant_ident)
|
||||
},
|
||||
Style::Newtype if variant.attrs.deserialize_with().is_none() => {
|
||||
let span = variant.original.span();
|
||||
let func = quote_spanned!(span=> _serde::#private::de::missing_field);
|
||||
quote! {
|
||||
#func(#content).map(#this_value::#variant_ident)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
missing_content_fallthrough = quote!(_ => #missing_content);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(quote! {
|
||||
__Field::#variant_index => #arm,
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !missing_content_arms.is_empty() {
|
||||
missing_content = quote! {
|
||||
match __field {
|
||||
#(#missing_content_arms)*
|
||||
#missing_content_fallthrough
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Advance the map by one key, returning early in case of error.
|
||||
let next_key = quote! {
|
||||
_serde::de::MapAccess::next_key_seed(&mut __map, #field_visitor_ty {
|
||||
tag: #tag,
|
||||
content: #content,
|
||||
})?
|
||||
};
|
||||
|
||||
let variant_from_map = quote! {
|
||||
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> {
|
||||
enum_name: #rust_name,
|
||||
variants: VARIANTS,
|
||||
fields_enum: _serde::#private::PhantomData
|
||||
})?
|
||||
};
|
||||
|
||||
// When allowing unknown fields, we want to transparently step through keys
|
||||
// we don't care about until we find `tag`, `content`, or run out of keys.
|
||||
let next_relevant_key = if deny_unknown_fields {
|
||||
next_key
|
||||
} else {
|
||||
quote!({
|
||||
let mut __rk : _serde::#private::Option<_serde::#private::de::TagOrContentField> = _serde::#private::None;
|
||||
while let _serde::#private::Some(__k) = #next_key {
|
||||
match __k {
|
||||
_serde::#private::de::TagContentOtherField::Other => {
|
||||
let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
|
||||
continue;
|
||||
},
|
||||
_serde::#private::de::TagContentOtherField::Tag => {
|
||||
__rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag);
|
||||
break;
|
||||
}
|
||||
_serde::#private::de::TagContentOtherField::Content => {
|
||||
__rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Content);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__rk
|
||||
})
|
||||
};
|
||||
|
||||
// Step through remaining keys, looking for duplicates of previously-seen
|
||||
// keys. When unknown fields are denied, any key that isn't a duplicate will
|
||||
// at this point immediately produce an error.
|
||||
let visit_remaining_keys = quote! {
|
||||
match #next_relevant_key {
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
|
||||
}
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content))
|
||||
}
|
||||
_serde::#private::None => _serde::#private::Ok(__ret),
|
||||
}
|
||||
};
|
||||
|
||||
let finish_content_then_tag = if variant_arms.is_empty() {
|
||||
quote! {
|
||||
match #variant_from_map {}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let __seed = __Seed {
|
||||
variant: #variant_from_map,
|
||||
marker: _serde::#private::PhantomData,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
};
|
||||
let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content);
|
||||
let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?;
|
||||
// Visit remaining keys, looking for duplicates.
|
||||
#visit_remaining_keys
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#variant_visitor
|
||||
|
||||
#variants_stmt
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __Seed #de_impl_generics #where_clause {
|
||||
variant: __Field,
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
|
||||
where
|
||||
__D: _serde::Deserializer<#delife>,
|
||||
{
|
||||
match self.variant {
|
||||
#(#variant_arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::MapAccess<#delife>,
|
||||
{
|
||||
// Visit the first relevant key.
|
||||
match #next_relevant_key {
|
||||
// First key is the tag.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
|
||||
// Parse the tag.
|
||||
let __field = #variant_from_map;
|
||||
// Visit the second key.
|
||||
match #next_relevant_key {
|
||||
// Second key is a duplicate of the tag.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag))
|
||||
}
|
||||
// Second key is the content.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
|
||||
let __ret = _serde::de::MapAccess::next_value_seed(&mut __map,
|
||||
__Seed {
|
||||
variant: __field,
|
||||
marker: _serde::#private::PhantomData,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
})?;
|
||||
// Visit remaining keys, looking for duplicates.
|
||||
#visit_remaining_keys
|
||||
}
|
||||
// There is no second key; might be okay if the we have a unit variant.
|
||||
_serde::#private::None => #missing_content
|
||||
}
|
||||
}
|
||||
// First key is the content.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
|
||||
// Buffer up the content.
|
||||
let __content = _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?;
|
||||
// Visit the second key.
|
||||
match #next_relevant_key {
|
||||
// Second key is the tag.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => {
|
||||
#finish_content_then_tag
|
||||
}
|
||||
// Second key is a duplicate of the content.
|
||||
_serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content))
|
||||
}
|
||||
// There is no second key.
|
||||
_serde::#private::None => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag))
|
||||
}
|
||||
}
|
||||
}
|
||||
// There is no first key.
|
||||
_serde::#private::None => {
|
||||
_serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_seq<__A>(self, mut __seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
// Visit the first element - the tag.
|
||||
match _serde::de::SeqAccess::next_element(&mut __seq)? {
|
||||
_serde::#private::Some(__variant) => {
|
||||
// Visit the second element - the content.
|
||||
match _serde::de::SeqAccess::next_element_seed(
|
||||
&mut __seq,
|
||||
__Seed {
|
||||
variant: __variant,
|
||||
marker: _serde::#private::PhantomData,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
},
|
||||
)? {
|
||||
_serde::#private::Some(__ret) => _serde::#private::Ok(__ret),
|
||||
// There is no second element.
|
||||
_serde::#private::None => {
|
||||
_serde::#private::Err(_serde::de::Error::invalid_length(1, &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
// There is no first element.
|
||||
_serde::#private::None => {
|
||||
_serde::#private::Err(_serde::de::Error::invalid_length(0, &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[#tag, #content];
|
||||
_serde::Deserializer::deserialize_struct(
|
||||
__deserializer,
|
||||
#type_name,
|
||||
FIELDS,
|
||||
__Visitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
//! Deserialization for externally tagged enums:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! enum Enum {}
|
||||
//! ```
|
||||
|
||||
use crate::de::enum_;
|
||||
use crate::de::struct_;
|
||||
use crate::de::tuple;
|
||||
use crate::de::{
|
||||
expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with,
|
||||
wrap_deserialize_with, Parameters, StructForm, TupleForm,
|
||||
};
|
||||
use crate::fragment::{Expr, Fragment, Match};
|
||||
use crate::internals::ast::{Field, Style, Variant};
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
let this_type = ¶ms.this_type;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let expecting = format!("enum {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
|
||||
|
||||
// Match arms to extract a variant from a string
|
||||
let variant_arms = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||
.map(|(i, variant)| {
|
||||
let variant_name = field_i(i);
|
||||
|
||||
let block = Match(deserialize_externally_tagged_variant(
|
||||
params, variant, cattrs,
|
||||
));
|
||||
|
||||
quote! {
|
||||
(__Field::#variant_name, __variant) => #block
|
||||
}
|
||||
});
|
||||
|
||||
let all_skipped = variants
|
||||
.iter()
|
||||
.all(|variant| variant.attrs.skip_deserializing());
|
||||
let match_variant = if all_skipped {
|
||||
// This is an empty enum like `enum Impossible {}` or an enum in which
|
||||
// all variants have `#[serde(skip_deserializing)]`.
|
||||
quote! {
|
||||
// FIXME: Once feature(exhaustive_patterns) is stable:
|
||||
// let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data);
|
||||
// _serde::#private::Err(__err)
|
||||
_serde::#private::Result::map(
|
||||
_serde::de::EnumAccess::variant::<__Field>(__data),
|
||||
|(__impossible, _)| match __impossible {})
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
match _serde::de::EnumAccess::variant(__data)? {
|
||||
#(#variant_arms)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#variant_visitor
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::EnumAccess<#delife>,
|
||||
{
|
||||
#match_variant
|
||||
}
|
||||
}
|
||||
|
||||
#variants_stmt
|
||||
|
||||
_serde::Deserializer::deserialize_enum(
|
||||
__deserializer,
|
||||
#type_name,
|
||||
VARIANTS,
|
||||
__Visitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_externally_tagged_variant(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
|
||||
return quote_block! {
|
||||
#wrapper
|
||||
_serde::#private::Result::map(
|
||||
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match variant.style {
|
||||
Style::Unit => {
|
||||
let this_value = ¶ms.this_value;
|
||||
quote_block! {
|
||||
_serde::de::VariantAccess::unit_variant(__variant)?;
|
||||
_serde::#private::Ok(#this_value::#variant_ident)
|
||||
}
|
||||
}
|
||||
Style::Newtype => deserialize_externally_tagged_newtype_variant(
|
||||
variant_ident,
|
||||
params,
|
||||
&variant.fields[0],
|
||||
cattrs,
|
||||
),
|
||||
Style::Tuple => tuple::deserialize(
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
TupleForm::ExternallyTagged(variant_ident),
|
||||
),
|
||||
Style::Struct => struct_::deserialize(
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
StructForm::ExternallyTagged(variant_ident),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_deserialize_variant_with(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
deserialize_with: &syn::ExprPath,
|
||||
) -> (TokenStream, TokenStream, TokenStream) {
|
||||
let field_tys = variant.fields.iter().map(|field| field.ty);
|
||||
let (wrapper, wrapper_ty) =
|
||||
wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with);
|
||||
|
||||
let unwrap_fn = unwrap_to_variant_closure(params, variant, true);
|
||||
|
||||
(wrapper, wrapper_ty, unwrap_fn)
|
||||
}
|
||||
|
||||
fn deserialize_externally_tagged_newtype_variant(
|
||||
variant_ident: &syn::Ident,
|
||||
params: &Parameters,
|
||||
field: &Field,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
let this_value = ¶ms.this_value;
|
||||
|
||||
if field.attrs.skip_deserializing() {
|
||||
let default = Expr(expr_is_missing(field, cattrs));
|
||||
return quote_block! {
|
||||
_serde::de::VariantAccess::unit_variant(__variant)?;
|
||||
_serde::#private::Ok(#this_value::#variant_ident(#default))
|
||||
};
|
||||
}
|
||||
|
||||
match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = field.ty;
|
||||
let span = field.original.span();
|
||||
let func =
|
||||
quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>);
|
||||
quote_expr! {
|
||||
_serde::#private::Result::map(#func(__variant), #this_value::#variant_ident)
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote_block! {
|
||||
#wrapper
|
||||
_serde::#private::Result::map(
|
||||
_serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant),
|
||||
|__wrapper| #this_value::#variant_ident(__wrapper.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
//! Deserialization for internally tagged enums:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! #[serde(tag = "...")]
|
||||
//! enum Enum {}
|
||||
//! ```
|
||||
|
||||
use crate::de::enum_;
|
||||
use crate::de::enum_untagged;
|
||||
use crate::de::struct_;
|
||||
use crate::de::{
|
||||
effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm,
|
||||
};
|
||||
use crate::fragment::{Expr, Fragment, Match};
|
||||
use crate::internals::ast::{Style, Variant};
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use quote::quote;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
tag: &str,
|
||||
) -> Fragment {
|
||||
let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
|
||||
|
||||
// Match arms to extract a variant from a string
|
||||
let variant_arms = variants
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
|
||||
.map(|(i, variant)| {
|
||||
let variant_name = field_i(i);
|
||||
|
||||
let block = Match(deserialize_internally_tagged_variant(
|
||||
params, variant, cattrs,
|
||||
));
|
||||
|
||||
quote! {
|
||||
__Field::#variant_name => #block
|
||||
}
|
||||
});
|
||||
|
||||
let expecting = format!("internally tagged enum {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
quote_block! {
|
||||
#variant_visitor
|
||||
|
||||
#variants_stmt
|
||||
|
||||
let (__tag, __content) = _serde::Deserializer::deserialize_any(
|
||||
__deserializer,
|
||||
_serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?;
|
||||
let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content);
|
||||
|
||||
match __tag {
|
||||
#(#variant_arms)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generates significant part of the visit_seq and visit_map bodies of visitors
|
||||
// for the variants of internally tagged enum.
|
||||
fn deserialize_internally_tagged_variant(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
|
||||
return quote_block! {
|
||||
_serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
let this_value = ¶ms.this_value;
|
||||
let type_name = params.type_name();
|
||||
let variant_name = variant.ident.to_string();
|
||||
let default = variant.fields.first().map(|field| {
|
||||
let default = Expr(expr_is_missing(field, cattrs));
|
||||
quote!((#default))
|
||||
});
|
||||
quote_block! {
|
||||
_serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?;
|
||||
_serde::#private::Ok(#this_value::#variant_ident #default)
|
||||
}
|
||||
}
|
||||
Style::Newtype => {
|
||||
enum_untagged::deserialize_newtype_variant(variant_ident, params, &variant.fields[0])
|
||||
}
|
||||
Style::Struct => struct_::deserialize(
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
StructForm::InternallyTagged(variant_ident),
|
||||
),
|
||||
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
//! Deserialization for untagged enums:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! #[serde(untagged)]
|
||||
//! enum Enum {}
|
||||
//! ```
|
||||
|
||||
use crate::de::struct_;
|
||||
use crate::de::tuple;
|
||||
use crate::de::{
|
||||
effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm,
|
||||
};
|
||||
use crate::fragment::{Expr, Fragment};
|
||||
use crate::internals::ast::{Field, Style, Variant};
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
first_attempt: Option<TokenStream>,
|
||||
) -> Fragment {
|
||||
let attempts = variants
|
||||
.iter()
|
||||
.filter(|variant| !variant.attrs.skip_deserializing())
|
||||
.map(|variant| Expr(deserialize_variant(params, variant, cattrs)));
|
||||
// TODO this message could be better by saving the errors from the failed
|
||||
// attempts. The heuristic used by TOML was to count the number of fields
|
||||
// processed before an error, and use the error that happened after the
|
||||
// largest number of fields. I'm not sure I like that. Maybe it would be
|
||||
// better to save all the errors and combine them into one message that
|
||||
// explains why none of the variants matched.
|
||||
let fallthrough_msg = format!(
|
||||
"data did not match any variant of untagged enum {}",
|
||||
params.type_name()
|
||||
);
|
||||
let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
|
||||
|
||||
let private2 = private;
|
||||
quote_block! {
|
||||
let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?;
|
||||
let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
|
||||
|
||||
#first_attempt
|
||||
|
||||
#(
|
||||
if let _serde::#private2::Ok(__ok) = #attempts {
|
||||
return _serde::#private2::Ok(__ok);
|
||||
}
|
||||
)*
|
||||
|
||||
_serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg))
|
||||
}
|
||||
}
|
||||
|
||||
// Also used by adjacently tagged enums
|
||||
pub(super) fn deserialize_variant(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
if let Some(path) = variant.attrs.deserialize_with() {
|
||||
let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
|
||||
return quote_block! {
|
||||
_serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
|
||||
};
|
||||
}
|
||||
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
let this_value = ¶ms.this_value;
|
||||
let type_name = params.type_name();
|
||||
let variant_name = variant.ident.to_string();
|
||||
let default = variant.fields.first().map(|field| {
|
||||
let default = Expr(expr_is_missing(field, cattrs));
|
||||
quote!((#default))
|
||||
});
|
||||
quote_expr! {
|
||||
match _serde::Deserializer::deserialize_any(
|
||||
__deserializer,
|
||||
_serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name)
|
||||
) {
|
||||
_serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default),
|
||||
_serde::#private::Err(__err) => _serde::#private::Err(__err),
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Newtype => deserialize_newtype_variant(variant_ident, params, &variant.fields[0]),
|
||||
Style::Tuple => tuple::deserialize(
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
TupleForm::Untagged(variant_ident),
|
||||
),
|
||||
Style::Struct => struct_::deserialize(
|
||||
params,
|
||||
&variant.fields,
|
||||
cattrs,
|
||||
StructForm::Untagged(variant_ident),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Also used by internally tagged enums
|
||||
// Implicitly (via `generate_variant`) used by adjacently tagged enums
|
||||
pub(super) fn deserialize_newtype_variant(
|
||||
variant_ident: &syn::Ident,
|
||||
params: &Parameters,
|
||||
field: &Field,
|
||||
) -> Fragment {
|
||||
let this_value = ¶ms.this_value;
|
||||
let field_ty = field.ty;
|
||||
match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
|
||||
quote_expr! {
|
||||
_serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident)
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
quote_block! {
|
||||
let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer);
|
||||
_serde::#private::Result::map(__value, #this_value::#variant_ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
//! Deserialization of struct field identifiers and enum variant identifiers by
|
||||
//! way of a Rust enum.
|
||||
|
||||
use crate::de::{FieldWithAliases, Parameters};
|
||||
use crate::fragment::{Fragment, Stmts};
|
||||
use crate::internals::ast::{Style, Variant};
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::{Literal, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
// Generates `Deserialize::deserialize` body for an enum with
|
||||
// `serde(field_identifier)` or `serde(variant_identifier)` attribute.
|
||||
pub(super) fn deserialize_custom(
|
||||
params: &Parameters,
|
||||
variants: &[Variant],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
let is_variant = match cattrs.identifier() {
|
||||
attr::Identifier::Variant => true,
|
||||
attr::Identifier::Field => false,
|
||||
attr::Identifier::No => unreachable!(),
|
||||
};
|
||||
|
||||
let this_type = params.this_type.to_token_stream();
|
||||
let this_value = params.this_value.to_token_stream();
|
||||
|
||||
let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() {
|
||||
let last_ident = &last.ident;
|
||||
if last.attrs.other() {
|
||||
// Process `serde(other)` attribute. It would always be found on the
|
||||
// last variant (checked in `check_identifier`), so all preceding
|
||||
// are ordinary variants.
|
||||
let ordinary = &variants[..variants.len() - 1];
|
||||
let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident));
|
||||
(ordinary, Some(fallthrough), None)
|
||||
} else if let Style::Newtype = last.style {
|
||||
let ordinary = &variants[..variants.len() - 1];
|
||||
let fallthrough = |value| {
|
||||
quote! {
|
||||
_serde::#private::Result::map(
|
||||
_serde::Deserialize::deserialize(
|
||||
_serde::#private::de::IdentifierDeserializer::from(#value)
|
||||
),
|
||||
#this_value::#last_ident)
|
||||
}
|
||||
};
|
||||
(
|
||||
ordinary,
|
||||
Some(fallthrough(quote!(__value))),
|
||||
Some(fallthrough(quote!(_serde::#private::de::Borrowed(
|
||||
__value
|
||||
)))),
|
||||
)
|
||||
} else {
|
||||
(variants, None, None)
|
||||
}
|
||||
} else {
|
||||
(variants, None, None)
|
||||
};
|
||||
|
||||
let idents_aliases: Vec<_> = ordinary
|
||||
.iter()
|
||||
.map(|variant| FieldWithAliases {
|
||||
ident: variant.ident.clone(),
|
||||
aliases: variant.attrs.aliases(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let names = idents_aliases.iter().flat_map(|variant| variant.aliases);
|
||||
|
||||
let names_const = if fallthrough.is_some() {
|
||||
None
|
||||
} else if is_variant {
|
||||
let variants = quote! {
|
||||
#[doc(hidden)]
|
||||
const VARIANTS: &'static [&'static str] = &[ #(#names),* ];
|
||||
};
|
||||
Some(variants)
|
||||
} else {
|
||||
let fields = quote! {
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[ #(#names),* ];
|
||||
};
|
||||
Some(fields)
|
||||
};
|
||||
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
let visitor_impl = Stmts(deserialize_identifier(
|
||||
&this_value,
|
||||
&idents_aliases,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
fallthrough_borrowed,
|
||||
false,
|
||||
cattrs.expecting(),
|
||||
));
|
||||
|
||||
quote_block! {
|
||||
#names_const
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __FieldVisitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
#visitor_impl
|
||||
}
|
||||
|
||||
let __visitor = __FieldVisitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
};
|
||||
_serde::Deserializer::deserialize_identifier(__deserializer, __visitor)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn deserialize_generated(
|
||||
deserialized_fields: &[FieldWithAliases],
|
||||
has_flatten: bool,
|
||||
is_variant: bool,
|
||||
ignore_variant: Option<TokenStream>,
|
||||
fallthrough: Option<TokenStream>,
|
||||
) -> Fragment {
|
||||
let this_value = quote!(__Field);
|
||||
let field_idents: &Vec<_> = &deserialized_fields
|
||||
.iter()
|
||||
.map(|field| &field.ident)
|
||||
.collect();
|
||||
|
||||
let visitor_impl = Stmts(deserialize_identifier(
|
||||
&this_value,
|
||||
deserialized_fields,
|
||||
is_variant,
|
||||
fallthrough,
|
||||
None,
|
||||
!is_variant && has_flatten,
|
||||
None,
|
||||
));
|
||||
|
||||
let lifetime = if !is_variant && has_flatten {
|
||||
Some(quote!(<'de>))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[doc(hidden)]
|
||||
enum __Field #lifetime {
|
||||
#(#field_idents,)*
|
||||
#ignore_variant
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __FieldVisitor;
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
|
||||
type Value = __Field #lifetime;
|
||||
|
||||
#visitor_impl
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'de> _serde::Deserialize<'de> for __Field #lifetime {
|
||||
#[inline]
|
||||
fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result<Self, __D::Error>
|
||||
where
|
||||
__D: _serde::Deserializer<'de>,
|
||||
{
|
||||
_serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_identifier(
|
||||
this_value: &TokenStream,
|
||||
deserialized_fields: &[FieldWithAliases],
|
||||
is_variant: bool,
|
||||
fallthrough: Option<TokenStream>,
|
||||
fallthrough_borrowed: Option<TokenStream>,
|
||||
collect_other_fields: bool,
|
||||
expecting: Option<&str>,
|
||||
) -> Fragment {
|
||||
let str_mapping = deserialized_fields.iter().map(|field| {
|
||||
let ident = &field.ident;
|
||||
let aliases = field.aliases;
|
||||
let private2 = private;
|
||||
// `aliases` also contains a main name
|
||||
quote! {
|
||||
#(
|
||||
#aliases => _serde::#private2::Ok(#this_value::#ident),
|
||||
)*
|
||||
}
|
||||
});
|
||||
let bytes_mapping = deserialized_fields.iter().map(|field| {
|
||||
let ident = &field.ident;
|
||||
// `aliases` also contains a main name
|
||||
let aliases = field
|
||||
.aliases
|
||||
.iter()
|
||||
.map(|alias| Literal::byte_string(alias.value.as_bytes()));
|
||||
let private2 = private;
|
||||
quote! {
|
||||
#(
|
||||
#aliases => _serde::#private2::Ok(#this_value::#ident),
|
||||
)*
|
||||
}
|
||||
});
|
||||
|
||||
let expecting = expecting.unwrap_or(if is_variant {
|
||||
"variant identifier"
|
||||
} else {
|
||||
"field identifier"
|
||||
});
|
||||
|
||||
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
let __value = &_serde::#private::from_utf8_lossy(__value);
|
||||
})
|
||||
};
|
||||
|
||||
let (
|
||||
value_as_str_content,
|
||||
value_as_borrowed_str_content,
|
||||
value_as_bytes_content,
|
||||
value_as_borrowed_bytes_content,
|
||||
) = if collect_other_fields {
|
||||
(
|
||||
Some(quote! {
|
||||
let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value));
|
||||
}),
|
||||
Some(quote! {
|
||||
let __value = _serde::#private::de::Content::Str(__value);
|
||||
}),
|
||||
Some(quote! {
|
||||
let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec());
|
||||
}),
|
||||
Some(quote! {
|
||||
let __value = _serde::#private::de::Content::Bytes(__value);
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(None, None, None, None)
|
||||
};
|
||||
|
||||
let fallthrough_arm_tokens;
|
||||
let fallthrough_arm = if let Some(fallthrough) = &fallthrough {
|
||||
fallthrough
|
||||
} else if is_variant {
|
||||
fallthrough_arm_tokens = quote! {
|
||||
_serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS))
|
||||
};
|
||||
&fallthrough_arm_tokens
|
||||
} else {
|
||||
fallthrough_arm_tokens = quote! {
|
||||
_serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS))
|
||||
};
|
||||
&fallthrough_arm_tokens
|
||||
};
|
||||
|
||||
let visit_other = if collect_other_fields {
|
||||
quote! {
|
||||
fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value)))
|
||||
}
|
||||
|
||||
fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value)))
|
||||
}
|
||||
|
||||
fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value)))
|
||||
}
|
||||
|
||||
fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value)))
|
||||
}
|
||||
|
||||
fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value)))
|
||||
}
|
||||
|
||||
fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value)))
|
||||
}
|
||||
|
||||
fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value)))
|
||||
}
|
||||
|
||||
fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value)))
|
||||
}
|
||||
|
||||
fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value)))
|
||||
}
|
||||
|
||||
fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value)))
|
||||
}
|
||||
|
||||
fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value)))
|
||||
}
|
||||
|
||||
fn visit_char<__E>(self, __value: char) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value)))
|
||||
}
|
||||
|
||||
fn visit_unit<__E>(self) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| {
|
||||
let i = i as u64;
|
||||
let ident = &field.ident;
|
||||
quote!(#i => _serde::#private::Ok(#this_value::#ident))
|
||||
});
|
||||
|
||||
let u64_fallthrough_arm_tokens;
|
||||
let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough {
|
||||
fallthrough
|
||||
} else {
|
||||
let index_expecting = if is_variant { "variant" } else { "field" };
|
||||
let fallthrough_msg = format!(
|
||||
"{} index 0 <= i < {}",
|
||||
index_expecting,
|
||||
deserialized_fields.len(),
|
||||
);
|
||||
u64_fallthrough_arm_tokens = quote! {
|
||||
_serde::#private::Err(_serde::de::Error::invalid_value(
|
||||
_serde::de::Unexpected::Unsigned(__value),
|
||||
&#fallthrough_msg,
|
||||
))
|
||||
};
|
||||
&u64_fallthrough_arm_tokens
|
||||
};
|
||||
|
||||
quote! {
|
||||
fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(#u64_mapping,)*
|
||||
_ => #u64_fallthrough_arm,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields {
|
||||
let str_mapping = str_mapping.clone();
|
||||
let bytes_mapping = bytes_mapping.clone();
|
||||
let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm);
|
||||
Some(quote! {
|
||||
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(#str_mapping)*
|
||||
_ => {
|
||||
#value_as_borrowed_str_content
|
||||
#fallthrough_borrowed_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(#bytes_mapping)*
|
||||
_ => {
|
||||
#bytes_to_str
|
||||
#value_as_borrowed_bytes_content
|
||||
#fallthrough_borrowed_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_other
|
||||
|
||||
fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(#str_mapping)*
|
||||
_ => {
|
||||
#value_as_str_content
|
||||
#fallthrough_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
match __value {
|
||||
#(#bytes_mapping)*
|
||||
_ => {
|
||||
#bytes_to_str
|
||||
#value_as_bytes_content
|
||||
#fallthrough_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#visit_borrowed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,697 @@
|
||||
use crate::de::identifier;
|
||||
use crate::de::{
|
||||
deserialize_seq, expr_is_missing, field_i, has_flatten, wrap_deserialize_field_with,
|
||||
FieldWithAliases, Parameters, StructForm,
|
||||
};
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
use crate::de::{deserialize_seq_in_place, place_lifetime};
|
||||
use crate::fragment::{Expr, Fragment, Match, Stmts};
|
||||
use crate::internals::ast::Field;
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for a `struct Struct {...}`
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
form: StructForm,
|
||||
) -> Fragment {
|
||||
let this_type = ¶ms.this_type;
|
||||
let this_value = ¶ms.this_value;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// If there are getters (implying private fields), construct the local type
|
||||
// and use an `Into` conversion to get the remote type. If there are no
|
||||
// getters then construct the target type directly.
|
||||
let construct = if params.has_getter {
|
||||
let local = ¶ms.local;
|
||||
quote!(#local)
|
||||
} else {
|
||||
quote!(#this_value)
|
||||
};
|
||||
|
||||
let type_path = match form {
|
||||
StructForm::Struct => construct,
|
||||
StructForm::ExternallyTagged(variant_ident)
|
||||
| StructForm::InternallyTagged(variant_ident)
|
||||
| StructForm::Untagged(variant_ident) => quote!(#construct::#variant_ident),
|
||||
};
|
||||
let expecting = match form {
|
||||
StructForm::Struct => format!("struct {}", params.type_name()),
|
||||
StructForm::ExternallyTagged(variant_ident)
|
||||
| StructForm::InternallyTagged(variant_ident)
|
||||
| StructForm::Untagged(variant_ident) => {
|
||||
format!("struct variant {}::{}", params.type_name(), variant_ident)
|
||||
}
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let deserialized_fields: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
// Skip fields that shouldn't be deserialized or that were flattened,
|
||||
// so they don't appear in the storage in their literal form
|
||||
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||
.map(|(i, field)| FieldWithAliases {
|
||||
ident: field_i(i),
|
||||
aliases: field.attrs.aliases(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let has_flatten = has_flatten(fields);
|
||||
let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, has_flatten);
|
||||
|
||||
// untagged struct variants do not get a visit_seq method. The same applies to
|
||||
// structs that only have a map representation.
|
||||
let visit_seq = match form {
|
||||
StructForm::Untagged(_) => None,
|
||||
_ if has_flatten => None,
|
||||
_ => {
|
||||
let mut_seq = if deserialized_fields.is_empty() {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq(
|
||||
&type_path, params, fields, true, cattrs, expecting,
|
||||
));
|
||||
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
let visit_map = Stmts(deserialize_map(
|
||||
&type_path,
|
||||
params,
|
||||
fields,
|
||||
cattrs,
|
||||
has_flatten,
|
||||
));
|
||||
|
||||
let visitor_seed = match form {
|
||||
StructForm::ExternallyTagged(..) if has_flatten => Some(quote! {
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result<Self::Value, __D::Error>
|
||||
where
|
||||
__D: _serde::Deserializer<#delife>,
|
||||
{
|
||||
_serde::Deserializer::deserialize_map(__deserializer, self)
|
||||
}
|
||||
}
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let fields_stmt = if has_flatten {
|
||||
None
|
||||
} else {
|
||||
let field_names = deserialized_fields.iter().flat_map(|field| field.aliases);
|
||||
|
||||
Some(quote! {
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||
})
|
||||
};
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
}
|
||||
};
|
||||
let dispatch = match form {
|
||||
StructForm::Struct if has_flatten => quote! {
|
||||
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
|
||||
},
|
||||
StructForm::Struct => {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
|
||||
}
|
||||
}
|
||||
StructForm::ExternallyTagged(_) if has_flatten => quote! {
|
||||
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
|
||||
},
|
||||
StructForm::ExternallyTagged(_) => quote! {
|
||||
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
|
||||
},
|
||||
StructForm::InternallyTagged(_) => quote! {
|
||||
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
|
||||
},
|
||||
StructForm::Untagged(_) => quote! {
|
||||
_serde::Deserializer::deserialize_any(__deserializer, #visitor_expr)
|
||||
},
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#field_visitor
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_seq
|
||||
|
||||
#[inline]
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::MapAccess<#delife>,
|
||||
{
|
||||
#visit_map
|
||||
}
|
||||
}
|
||||
|
||||
#visitor_seed
|
||||
|
||||
#fields_stmt
|
||||
|
||||
#dispatch
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_map(
|
||||
struct_path: &TokenStream,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
has_flatten: bool,
|
||||
) -> Fragment {
|
||||
// Create the field names for the fields.
|
||||
let fields_names: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| (field, field_i(i)))
|
||||
.collect();
|
||||
|
||||
// Declare each field that will be deserialized.
|
||||
let let_values = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||
.map(|(field, name)| {
|
||||
let field_ty = field.ty;
|
||||
quote! {
|
||||
let mut #name: _serde::#private::Option<#field_ty> = _serde::#private::None;
|
||||
}
|
||||
});
|
||||
|
||||
// Collect contents for flatten fields into a buffer
|
||||
let let_collect = if has_flatten {
|
||||
Some(quote! {
|
||||
let mut __collect = _serde::#private::Vec::<_serde::#private::Option<(
|
||||
_serde::#private::de::Content,
|
||||
_serde::#private::de::Content
|
||||
)>>::new();
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Match arms to extract a value for a field.
|
||||
let value_arms = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||
.map(|(field, name)| {
|
||||
let deser_name = field.attrs.name().deserialize_name();
|
||||
|
||||
let visit = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let field_ty = field.ty;
|
||||
let span = field.original.span();
|
||||
let func =
|
||||
quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>);
|
||||
quote! {
|
||||
#func(&mut __map)?
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) {
|
||||
_serde::#private::Ok(__wrapper) => __wrapper.value,
|
||||
_serde::#private::Err(__err) => {
|
||||
return _serde::#private::Err(__err);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
__Field::#name => {
|
||||
if _serde::#private::Option::is_some(&#name) {
|
||||
return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name));
|
||||
}
|
||||
#name = _serde::#private::Some(#visit);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Visit ignored values to consume them
|
||||
let ignored_arm = if has_flatten {
|
||||
Some(quote! {
|
||||
__Field::__other(__name) => {
|
||||
__collect.push(_serde::#private::Some((
|
||||
__name,
|
||||
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?)));
|
||||
}
|
||||
})
|
||||
} else if cattrs.deny_unknown_fields() {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
|
||||
})
|
||||
};
|
||||
|
||||
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
|
||||
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
|
||||
quote! {
|
||||
// FIXME: Once feature(exhaustive_patterns) is stable:
|
||||
// let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
|
||||
_serde::#private::Option::map(
|
||||
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|
||||
|__impossible| match __impossible {});
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
|
||||
match __key {
|
||||
#(#value_arms)*
|
||||
#ignored_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let extract_values = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
|
||||
.map(|(field, name)| {
|
||||
let missing_expr = Match(expr_is_missing(field, cattrs));
|
||||
|
||||
quote! {
|
||||
let #name = match #name {
|
||||
_serde::#private::Some(#name) => #name,
|
||||
_serde::#private::None => #missing_expr
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
let extract_collected = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing())
|
||||
.map(|(field, name)| {
|
||||
let field_ty = field.ty;
|
||||
let func = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let span = field.original.span();
|
||||
quote_spanned!(span=> _serde::de::Deserialize::deserialize)
|
||||
}
|
||||
Some(path) => quote!(#path),
|
||||
};
|
||||
quote! {
|
||||
let #name: #field_ty = #func(
|
||||
_serde::#private::de::FlatMapDeserializer(
|
||||
&mut __collect,
|
||||
_serde::#private::PhantomData))?;
|
||||
}
|
||||
});
|
||||
|
||||
let collected_deny_unknown_fields = if has_flatten && cattrs.deny_unknown_fields() {
|
||||
Some(quote! {
|
||||
if let _serde::#private::Some(_serde::#private::Some((__key, _))) =
|
||||
__collect.into_iter().filter(_serde::#private::Option::is_some).next()
|
||||
{
|
||||
if let _serde::#private::Some(__key) = _serde::#private::de::content_as_str(&__key) {
|
||||
return _serde::#private::Err(
|
||||
_serde::de::Error::custom(format_args!("unknown field `{}`", &__key)));
|
||||
} else {
|
||||
return _serde::#private::Err(
|
||||
_serde::de::Error::custom(format_args!("unexpected map key")));
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let result = fields_names.iter().map(|(field, name)| {
|
||||
let member = &field.member;
|
||||
if field.attrs.skip_deserializing() {
|
||||
let value = Expr(expr_is_missing(field, cattrs));
|
||||
quote!(#member: #value)
|
||||
} else {
|
||||
quote!(#member: #name)
|
||||
}
|
||||
});
|
||||
|
||||
let let_default = match cattrs.default() {
|
||||
attr::Default::Default => Some(quote!(
|
||||
let __default: Self::Value = _serde::#private::Default::default();
|
||||
)),
|
||||
// If #path returns wrong type, error will be reported here (^^^^^).
|
||||
// We attach span of the path to the function so it will be reported
|
||||
// on the #[serde(default = "...")]
|
||||
// ^^^^^
|
||||
attr::Default::Path(path) => Some(quote_spanned!(path.span()=>
|
||||
let __default: Self::Value = #path();
|
||||
)),
|
||||
attr::Default::None => {
|
||||
// We don't need the default value, to prevent an unused variable warning
|
||||
// we'll leave the line empty.
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = quote!(#struct_path { #(#result),* });
|
||||
if params.has_getter {
|
||||
let this_type = ¶ms.this_type;
|
||||
let (_, ty_generics, _) = params.generics.split_for_impl();
|
||||
result = quote! {
|
||||
_serde::#private::Into::<#this_type #ty_generics>::into(#result)
|
||||
};
|
||||
}
|
||||
|
||||
quote_block! {
|
||||
#(#let_values)*
|
||||
|
||||
#let_collect
|
||||
|
||||
#match_keys
|
||||
|
||||
#let_default
|
||||
|
||||
#(#extract_values)*
|
||||
|
||||
#(#extract_collected)*
|
||||
|
||||
#collected_deny_unknown_fields
|
||||
|
||||
_serde::#private::Ok(#result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}`
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
pub(super) fn deserialize_in_place(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> Option<Fragment> {
|
||||
// for now we do not support in_place deserialization for structs that
|
||||
// are represented as map.
|
||||
if has_flatten(fields) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let this_type = ¶ms.this_type;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let expecting = format!("struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let deserialized_fields: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||
.map(|(i, field)| FieldWithAliases {
|
||||
ident: field_i(i),
|
||||
aliases: field.attrs.aliases(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, false);
|
||||
|
||||
let mut_seq = if deserialized_fields.is_empty() {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
|
||||
let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs));
|
||||
let field_names = deserialized_fields.iter().flat_map(|field| field.aliases);
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
|
||||
let in_place_impl_generics = de_impl_generics.in_place();
|
||||
let in_place_ty_generics = de_ty_generics.in_place();
|
||||
let place_life = place_lifetime();
|
||||
|
||||
Some(quote_block! {
|
||||
#field_visitor
|
||||
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #in_place_impl_generics #where_clause {
|
||||
place: &#place_life mut #this_type #ty_generics,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::MapAccess<#delife>,
|
||||
{
|
||||
#visit_map
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||
|
||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor {
|
||||
place: __place,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_map_in_place(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
assert!(
|
||||
!has_flatten(fields),
|
||||
"inplace deserialization of maps does not support flatten fields"
|
||||
);
|
||||
|
||||
// Create the field names for the fields.
|
||||
let fields_names: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| (field, field_i(i)))
|
||||
.collect();
|
||||
|
||||
// For deserialize_in_place, declare booleans for each field that will be
|
||||
// deserialized.
|
||||
let let_flags = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|(_, name)| {
|
||||
quote! {
|
||||
let mut #name: bool = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Match arms to extract a value for a field.
|
||||
let value_arms_from = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|(field, name)| {
|
||||
let deser_name = field.attrs.name().deserialize_name();
|
||||
let member = &field.member;
|
||||
|
||||
let visit = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
quote! {
|
||||
_serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::InPlaceSeed(&mut self.place.#member))?
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
|
||||
quote!({
|
||||
#wrapper
|
||||
self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) {
|
||||
_serde::#private::Ok(__wrapper) => __wrapper.value,
|
||||
_serde::#private::Err(__err) => {
|
||||
return _serde::#private::Err(__err);
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
__Field::#name => {
|
||||
if #name {
|
||||
return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name));
|
||||
}
|
||||
#visit;
|
||||
#name = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Visit ignored values to consume them
|
||||
let ignored_arm = if cattrs.deny_unknown_fields() {
|
||||
None
|
||||
} else {
|
||||
Some(quote! {
|
||||
_ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; }
|
||||
})
|
||||
};
|
||||
|
||||
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
|
||||
|
||||
let match_keys = if cattrs.deny_unknown_fields() && all_skipped {
|
||||
quote! {
|
||||
// FIXME: Once feature(exhaustive_patterns) is stable:
|
||||
// let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?;
|
||||
_serde::#private::Option::map(
|
||||
_serde::de::MapAccess::next_key::<__Field>(&mut __map)?,
|
||||
|__impossible| match __impossible {});
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
|
||||
match __key {
|
||||
#(#value_arms_from)*
|
||||
#ignored_arm
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let check_flags = fields_names
|
||||
.iter()
|
||||
.filter(|&&(field, _)| !field.attrs.skip_deserializing())
|
||||
.map(|(field, name)| {
|
||||
let missing_expr = expr_is_missing(field, cattrs);
|
||||
// If missing_expr unconditionally returns an error, don't try
|
||||
// to assign its value to self.place.
|
||||
if field.attrs.default().is_none()
|
||||
&& cattrs.default().is_none()
|
||||
&& field.attrs.deserialize_with().is_some()
|
||||
{
|
||||
let missing_expr = Stmts(missing_expr);
|
||||
quote! {
|
||||
if !#name {
|
||||
#missing_expr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let member = &field.member;
|
||||
let missing_expr = Expr(missing_expr);
|
||||
quote! {
|
||||
if !#name {
|
||||
self.place.#member = #missing_expr;
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let this_type = ¶ms.this_type;
|
||||
let (_, ty_generics, _) = params.generics.split_for_impl();
|
||||
|
||||
let let_default = match cattrs.default() {
|
||||
attr::Default::Default => Some(quote!(
|
||||
let __default: #this_type #ty_generics = _serde::#private::Default::default();
|
||||
)),
|
||||
// If #path returns wrong type, error will be reported here (^^^^^).
|
||||
// We attach span of the path to the function so it will be reported
|
||||
// on the #[serde(default = "...")]
|
||||
// ^^^^^
|
||||
attr::Default::Path(path) => Some(quote_spanned!(path.span()=>
|
||||
let __default: #this_type #ty_generics = #path();
|
||||
)),
|
||||
attr::Default::None => {
|
||||
// We don't need the default value, to prevent an unused variable warning
|
||||
// we'll leave the line empty.
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#(#let_flags)*
|
||||
|
||||
#match_keys
|
||||
|
||||
#let_default
|
||||
|
||||
#(#check_flags)*
|
||||
|
||||
_serde::#private::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates enum and its `Deserialize` implementation that represents each
|
||||
/// non-skipped field of the struct
|
||||
fn deserialize_field_identifier(
|
||||
deserialized_fields: &[FieldWithAliases],
|
||||
cattrs: &attr::Container,
|
||||
has_flatten: bool,
|
||||
) -> Stmts {
|
||||
let (ignore_variant, fallthrough) = if has_flatten {
|
||||
let ignore_variant = quote!(__other(_serde::#private::de::Content<'de>),);
|
||||
let fallthrough = quote!(_serde::#private::Ok(__Field::__other(__value)));
|
||||
(Some(ignore_variant), Some(fallthrough))
|
||||
} else if cattrs.deny_unknown_fields() {
|
||||
(None, None)
|
||||
} else {
|
||||
let ignore_variant = quote!(__ignore,);
|
||||
let fallthrough = quote!(_serde::#private::Ok(__Field::__ignore));
|
||||
(Some(ignore_variant), Some(fallthrough))
|
||||
};
|
||||
|
||||
Stmts(identifier::deserialize_generated(
|
||||
deserialized_fields,
|
||||
has_flatten,
|
||||
false,
|
||||
ignore_variant,
|
||||
fallthrough,
|
||||
))
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
use crate::de::{deserialize_seq, has_flatten, Parameters, TupleForm};
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
use crate::de::{deserialize_seq_in_place, place_lifetime};
|
||||
use crate::fragment::{Fragment, Stmts};
|
||||
use crate::internals::ast::Field;
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);`
|
||||
pub(super) fn deserialize(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
form: TupleForm,
|
||||
) -> Fragment {
|
||||
assert!(
|
||||
!has_flatten(fields),
|
||||
"tuples and tuple variants cannot have flatten fields"
|
||||
);
|
||||
|
||||
let field_count = fields
|
||||
.iter()
|
||||
.filter(|field| !field.attrs.skip_deserializing())
|
||||
.count();
|
||||
|
||||
let this_type = ¶ms.this_type;
|
||||
let this_value = ¶ms.this_value;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
// If there are getters (implying private fields), construct the local type
|
||||
// and use an `Into` conversion to get the remote type. If there are no
|
||||
// getters then construct the target type directly.
|
||||
let construct = if params.has_getter {
|
||||
let local = ¶ms.local;
|
||||
quote!(#local)
|
||||
} else {
|
||||
quote!(#this_value)
|
||||
};
|
||||
|
||||
let type_path = match form {
|
||||
TupleForm::Tuple => construct,
|
||||
TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => {
|
||||
quote!(#construct::#variant_ident)
|
||||
}
|
||||
};
|
||||
let expecting = match form {
|
||||
TupleForm::Tuple => format!("tuple struct {}", params.type_name()),
|
||||
TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => {
|
||||
format!("tuple variant {}::{}", params.type_name(), variant_ident)
|
||||
}
|
||||
};
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
let visit_newtype_struct = match form {
|
||||
TupleForm::Tuple if nfields == 1 => {
|
||||
Some(deserialize_newtype_struct(&type_path, params, &fields[0]))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq(
|
||||
&type_path, params, fields, false, cattrs, expecting,
|
||||
));
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
}
|
||||
};
|
||||
let dispatch = match form {
|
||||
TupleForm::Tuple if nfields == 1 => {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)
|
||||
}
|
||||
}
|
||||
TupleForm::Tuple => {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)
|
||||
}
|
||||
}
|
||||
TupleForm::ExternallyTagged(_) => quote! {
|
||||
_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr)
|
||||
},
|
||||
TupleForm::Untagged(_) => quote! {
|
||||
_serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr)
|
||||
},
|
||||
};
|
||||
|
||||
let visitor_var = if field_count == 0 {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_newtype_struct
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
}
|
||||
|
||||
#dispatch
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct(
|
||||
type_path: &TokenStream,
|
||||
params: &Parameters,
|
||||
field: &Field,
|
||||
) -> TokenStream {
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
let field_ty = field.ty;
|
||||
let deserializer_var = quote!(__e);
|
||||
|
||||
let value = match field.attrs.deserialize_with() {
|
||||
None => {
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
|
||||
quote! {
|
||||
#func(#deserializer_var)?
|
||||
}
|
||||
}
|
||||
Some(path) => {
|
||||
// If #path returns wrong type, error will be reported here (^^^^^).
|
||||
// We attach span of the path to the function so it will be reported
|
||||
// on the #[serde(with = "...")]
|
||||
// ^^^^^
|
||||
quote_spanned! {path.span()=>
|
||||
#path(#deserializer_var)?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = quote!(#type_path(__field0));
|
||||
if params.has_getter {
|
||||
let this_type = ¶ms.this_type;
|
||||
let (_, ty_generics, _) = params.generics.split_for_impl();
|
||||
result = quote! {
|
||||
_serde::#private::Into::<#this_type #ty_generics>::into(#result)
|
||||
};
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result<Self::Value, __E::Error>
|
||||
where
|
||||
__E: _serde::Deserializer<#delife>,
|
||||
{
|
||||
let __field0: #field_ty = #value;
|
||||
_serde::#private::Ok(#result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);`
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
pub(super) fn deserialize_in_place(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> Fragment {
|
||||
assert!(
|
||||
!has_flatten(fields),
|
||||
"tuples and tuple variants cannot have flatten fields"
|
||||
);
|
||||
|
||||
let field_count = fields
|
||||
.iter()
|
||||
.filter(|field| !field.attrs.skip_deserializing())
|
||||
.count();
|
||||
|
||||
let this_type = ¶ms.this_type;
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let expecting = format!("tuple struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
let visit_newtype_struct = if nfields == 1 {
|
||||
// We do not generate deserialize_in_place if every field has a
|
||||
// deserialize_with.
|
||||
assert!(fields[0].attrs.deserialize_with().is_none());
|
||||
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::#private::Result<Self::Value, __E::Error>
|
||||
where
|
||||
__E: _serde::Deserializer<#delife>,
|
||||
{
|
||||
_serde::Deserialize::deserialize_in_place(__e, &mut self.place.0)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
place: __place,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
}
|
||||
};
|
||||
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let dispatch = if nfields == 1 {
|
||||
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
|
||||
} else {
|
||||
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
|
||||
};
|
||||
|
||||
let visitor_var = if field_count == 0 {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
let in_place_impl_generics = de_impl_generics.in_place();
|
||||
let in_place_ty_generics = de_ty_generics.in_place();
|
||||
let place_life = place_lifetime();
|
||||
|
||||
quote_block! {
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #in_place_impl_generics #where_clause {
|
||||
place: &#place_life mut #this_type #ty_generics,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_newtype_struct
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
}
|
||||
|
||||
#dispatch
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use crate::de::Parameters;
|
||||
use crate::fragment::Fragment;
|
||||
use crate::internals::attr;
|
||||
use crate::private;
|
||||
use quote::quote;
|
||||
|
||||
/// Generates `Deserialize::deserialize` body for a `struct Unit;`
|
||||
pub(super) fn deserialize(params: &Parameters, cattrs: &attr::Container) -> Fragment {
|
||||
let this_type = ¶ms.this_type;
|
||||
let this_value = ¶ms.this_value;
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
|
||||
params.generics_with_de_lifetime();
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let expecting = format!("unit struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
quote_block! {
|
||||
#[doc(hidden)]
|
||||
struct __Visitor #de_impl_generics #where_clause {
|
||||
marker: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData<&#delife ()>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||
type Value = #this_type #ty_generics;
|
||||
|
||||
fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
|
||||
_serde::#private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<__E>(self) -> _serde::#private::Result<Self::Value, __E>
|
||||
where
|
||||
__E: _serde::de::Error,
|
||||
{
|
||||
_serde::#private::Ok(#this_value)
|
||||
}
|
||||
}
|
||||
|
||||
_serde::Deserializer::deserialize_unit_struct(
|
||||
__deserializer,
|
||||
#type_name,
|
||||
__Visitor {
|
||||
marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
lifetime: _serde::#private::PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub fn allow_deprecated(input: &syn::DeriveInput) -> Option<TokenStream> {
|
||||
if should_allow_deprecated(input) {
|
||||
Some(quote! { #[allow(deprecated)] })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if an `#[allow(deprecated)]` should be added to the derived impl.
|
||||
///
|
||||
/// This should happen if the derive input or an enum variant it contains has
|
||||
/// one of:
|
||||
/// - `#[deprecated]`
|
||||
/// - `#[allow(deprecated)]`
|
||||
fn should_allow_deprecated(input: &syn::DeriveInput) -> bool {
|
||||
if contains_deprecated(&input.attrs) {
|
||||
return true;
|
||||
}
|
||||
if let syn::Data::Enum(data_enum) = &input.data {
|
||||
for variant in &data_enum.variants {
|
||||
if contains_deprecated(&variant.attrs) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check whether the given attributes contains one of:
|
||||
/// - `#[deprecated]`
|
||||
/// - `#[allow(deprecated)]`
|
||||
fn contains_deprecated(attrs: &[syn::Attribute]) -> bool {
|
||||
for attr in attrs {
|
||||
if attr.path().is_ident("deprecated") {
|
||||
return true;
|
||||
}
|
||||
if let syn::Meta::List(meta_list) = &attr.meta {
|
||||
if meta_list.path.is_ident("allow") {
|
||||
let mut allow_deprecated = false;
|
||||
let _ = meta_list.parse_nested_meta(|meta| {
|
||||
if meta.path.is_ident("deprecated") {
|
||||
allow_deprecated = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
if allow_deprecated {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
@@ -14,9 +14,17 @@ pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> Token
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||
#[allow(
|
||||
non_upper_case_globals,
|
||||
unused_attributes,
|
||||
unused_qualifications,
|
||||
clippy::absolute_paths,
|
||||
)]
|
||||
const _: () = {
|
||||
#use_serde
|
||||
|
||||
_serde::__require_serde_not_serde_core!();
|
||||
|
||||
#code
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
|
||||
|
||||
use crate::internals::{attr, check, Ctxt, Derive};
|
||||
use proc_macro2::Ident;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::Token;
|
||||
|
||||
@@ -62,13 +63,17 @@ impl<'a> Container<'a> {
|
||||
cx: &Ctxt,
|
||||
item: &'a syn::DeriveInput,
|
||||
derive: Derive,
|
||||
private: &Ident,
|
||||
) -> Option<Container<'a>> {
|
||||
let mut attrs = attr::Container::from_ast(cx, item);
|
||||
let attrs = attr::Container::from_ast(cx, item);
|
||||
|
||||
let mut data = match &item.data {
|
||||
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
|
||||
syn::Data::Enum(data) => {
|
||||
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default(), private))
|
||||
}
|
||||
syn::Data::Struct(data) => {
|
||||
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &data.fields, None, attrs.default(), private);
|
||||
Data::Struct(style, fields)
|
||||
}
|
||||
syn::Data::Union(_) => {
|
||||
@@ -77,15 +82,11 @@ impl<'a> Container<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut has_flatten = false;
|
||||
match &mut data {
|
||||
Data::Enum(variants) => {
|
||||
for variant in variants {
|
||||
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
for field in &mut variant.fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rules(
|
||||
variant
|
||||
.attrs
|
||||
@@ -97,18 +98,11 @@ impl<'a> Container<'a> {
|
||||
}
|
||||
Data::Struct(_, fields) => {
|
||||
for field in fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if has_flatten {
|
||||
attrs.mark_has_flatten();
|
||||
}
|
||||
|
||||
let mut item = Container {
|
||||
ident: item.ident.clone(),
|
||||
attrs,
|
||||
@@ -140,13 +134,19 @@ fn enum_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||
container_default: &attr::Default,
|
||||
private: &Ident,
|
||||
) -> Vec<Variant<'a>> {
|
||||
let variants: Vec<Variant> = variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||
let (style, fields) = struct_from_ast(
|
||||
cx,
|
||||
&variant.fields,
|
||||
Some(&attrs),
|
||||
container_default,
|
||||
private,
|
||||
);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs,
|
||||
@@ -176,19 +176,20 @@ fn struct_from_ast<'a>(
|
||||
fields: &'a syn::Fields,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
private: &Ident,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match fields {
|
||||
syn::Fields::Named(fields) => (
|
||||
Style::Struct,
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default, private),
|
||||
),
|
||||
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default, private),
|
||||
),
|
||||
syn::Fields::Unnamed(fields) => (
|
||||
Style::Tuple,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default, private),
|
||||
),
|
||||
syn::Fields::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
@@ -199,6 +200,7 @@ fn fields_from_ast<'a>(
|
||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
private: &Ident,
|
||||
) -> Vec<Field<'a>> {
|
||||
fields
|
||||
.iter()
|
||||
@@ -208,7 +210,7 @@ fn fields_from_ast<'a>(
|
||||
Some(ident) => syn::Member::Named(ident.clone()),
|
||||
None => syn::Member::Unnamed(i.into()),
|
||||
},
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default, private),
|
||||
ty: &field.ty,
|
||||
original: field,
|
||||
})
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use crate::internals::name::{MultiName, Name};
|
||||
use crate::internals::symbol::*;
|
||||
use crate::internals::{ungroup, Ctxt};
|
||||
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
|
||||
use quote::ToTokens;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::iter::FromIterator;
|
||||
use syn::meta::ParseNestedMeta;
|
||||
use syn::parse::ParseStream;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{parse_quote, token, Ident, Lifetime, Token};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{token, Ident, Lifetime, Token};
|
||||
|
||||
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
|
||||
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
|
||||
@@ -20,7 +21,7 @@ use syn::{parse_quote, token, Ident, Lifetime, Token};
|
||||
|
||||
pub use crate::internals::case::RenameRule;
|
||||
|
||||
struct Attr<'c, T> {
|
||||
pub(crate) struct Attr<'c, T> {
|
||||
cx: &'c Ctxt,
|
||||
name: Symbol,
|
||||
tokens: TokenStream,
|
||||
@@ -61,7 +62,7 @@ impl<'c, T> Attr<'c, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get(self) -> Option<T> {
|
||||
pub(crate) fn get(self) -> Option<T> {
|
||||
self.value
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ impl<'c> BoolAttr<'c> {
|
||||
}
|
||||
}
|
||||
|
||||
struct VecAttr<'c, T> {
|
||||
pub(crate) struct VecAttr<'c, T> {
|
||||
cx: &'c Ctxt,
|
||||
name: Symbol,
|
||||
first_dup_tokens: TokenStream,
|
||||
@@ -124,69 +125,19 @@ impl<'c, T> VecAttr<'c, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get(self) -> Vec<T> {
|
||||
pub(crate) fn get(self) -> Vec<T> {
|
||||
self.values
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Name {
|
||||
serialize: String,
|
||||
serialize_renamed: bool,
|
||||
deserialize: String,
|
||||
deserialize_renamed: bool,
|
||||
deserialize_aliases: BTreeSet<String>,
|
||||
}
|
||||
|
||||
fn unraw(ident: &Ident) -> String {
|
||||
ident.to_string().trim_start_matches("r#").to_owned()
|
||||
}
|
||||
|
||||
impl Name {
|
||||
fn from_attrs(
|
||||
source_name: String,
|
||||
ser_name: Attr<String>,
|
||||
de_name: Attr<String>,
|
||||
de_aliases: Option<VecAttr<String>>,
|
||||
) -> Name {
|
||||
let mut alias_set = BTreeSet::new();
|
||||
if let Some(de_aliases) = de_aliases {
|
||||
for alias_name in de_aliases.get() {
|
||||
alias_set.insert(alias_name);
|
||||
}
|
||||
}
|
||||
|
||||
let ser_name = ser_name.get();
|
||||
let ser_renamed = ser_name.is_some();
|
||||
let de_name = de_name.get();
|
||||
let de_renamed = de_name.is_some();
|
||||
Name {
|
||||
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
|
||||
serialize_renamed: ser_renamed,
|
||||
deserialize: de_name.unwrap_or(source_name),
|
||||
deserialize_renamed: de_renamed,
|
||||
deserialize_aliases: alias_set,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the container name for the container when serializing.
|
||||
pub fn serialize_name(&self) -> &str {
|
||||
&self.serialize
|
||||
}
|
||||
|
||||
/// Return the container name for the container when deserializing.
|
||||
pub fn deserialize_name(&self) -> &str {
|
||||
&self.deserialize
|
||||
}
|
||||
|
||||
fn deserialize_aliases(&self) -> &BTreeSet<String> {
|
||||
&self.deserialize_aliases
|
||||
}
|
||||
fn unraw(ident: &Ident) -> Ident {
|
||||
Ident::new(ident.to_string().trim_start_matches("r#"), ident.span())
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RenameAllRules {
|
||||
serialize: RenameRule,
|
||||
deserialize: RenameRule,
|
||||
pub serialize: RenameRule,
|
||||
pub deserialize: RenameRule,
|
||||
}
|
||||
|
||||
impl RenameAllRules {
|
||||
@@ -202,7 +153,7 @@ impl RenameAllRules {
|
||||
|
||||
/// Represents struct or enum attribute information.
|
||||
pub struct Container {
|
||||
name: Name,
|
||||
name: MultiName,
|
||||
transparent: bool,
|
||||
deny_unknown_fields: bool,
|
||||
default: Default,
|
||||
@@ -216,7 +167,6 @@ pub struct Container {
|
||||
type_into: Option<syn::Type>,
|
||||
remote: Option<syn::Path>,
|
||||
identifier: Identifier,
|
||||
has_flatten: bool,
|
||||
serde_path: Option<syn::Path>,
|
||||
is_packed: bool,
|
||||
/// Error message generated when type can't be deserialized
|
||||
@@ -327,8 +277,8 @@ impl Container {
|
||||
// #[serde(rename = "foo")]
|
||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||
let (ser, de) = get_renames(cx, RENAME, &meta)?;
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
|
||||
de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value));
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
|
||||
de_name.set_opt(&meta.path, de.as_ref().map(Name::from));
|
||||
} else if meta.path == RENAME_ALL {
|
||||
// #[serde(rename_all = "foo")]
|
||||
// #[serde(rename_all(serialize = "foo", deserialize = "bar"))]
|
||||
@@ -567,7 +517,7 @@ impl Container {
|
||||
}
|
||||
|
||||
Container {
|
||||
name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None),
|
||||
name: MultiName::from_attrs(Name::from(&unraw(&item.ident)), ser_name, de_name, None),
|
||||
transparent: transparent.get(),
|
||||
deny_unknown_fields: deny_unknown_fields.get(),
|
||||
default: default.get().unwrap_or(Default::None),
|
||||
@@ -587,7 +537,6 @@ impl Container {
|
||||
type_into: type_into.get(),
|
||||
remote: remote.get(),
|
||||
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
||||
has_flatten: false,
|
||||
serde_path: serde_path.get(),
|
||||
is_packed,
|
||||
expecting: expecting.get(),
|
||||
@@ -595,7 +544,7 @@ impl Container {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
pub fn name(&self) -> &MultiName {
|
||||
&self.name
|
||||
}
|
||||
|
||||
@@ -655,23 +604,10 @@ impl Container {
|
||||
self.identifier
|
||||
}
|
||||
|
||||
pub fn has_flatten(&self) -> bool {
|
||||
self.has_flatten
|
||||
}
|
||||
|
||||
pub fn mark_has_flatten(&mut self) {
|
||||
self.has_flatten = true;
|
||||
}
|
||||
|
||||
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
|
||||
self.serde_path.as_ref()
|
||||
}
|
||||
|
||||
pub fn serde_path(&self) -> Cow<syn::Path> {
|
||||
self.custom_serde_path()
|
||||
.map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed)
|
||||
}
|
||||
|
||||
/// Error message generated when type can't be deserialized.
|
||||
/// If `None`, default message will be used
|
||||
pub fn expecting(&self) -> Option<&str> {
|
||||
@@ -790,7 +726,7 @@ fn decide_identifier(
|
||||
|
||||
/// Represents variant attribute information
|
||||
pub struct Variant {
|
||||
name: Name,
|
||||
name: MultiName,
|
||||
rename_all_rules: RenameAllRules,
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
@@ -841,15 +777,15 @@ impl Variant {
|
||||
// #[serde(rename = "foo")]
|
||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||
let (ser, de) = get_multiple_renames(cx, &meta)?;
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
|
||||
for de_value in de {
|
||||
de_name.set_if_none(de_value.value());
|
||||
de_aliases.insert(&meta.path, de_value.value());
|
||||
de_name.set_if_none(Name::from(&de_value));
|
||||
de_aliases.insert(&meta.path, Name::from(&de_value));
|
||||
}
|
||||
} else if meta.path == ALIAS {
|
||||
// #[serde(alias = "foo")]
|
||||
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
|
||||
de_aliases.insert(&meta.path, s.value());
|
||||
de_aliases.insert(&meta.path, Name::from(&s));
|
||||
}
|
||||
} else if meta.path == RENAME_ALL {
|
||||
// #[serde(rename_all = "foo")]
|
||||
@@ -898,13 +834,13 @@ impl Variant {
|
||||
ser_path
|
||||
.path
|
||||
.segments
|
||||
.push(Ident::new("serialize", Span::call_site()).into());
|
||||
.push(Ident::new("serialize", ser_path.span()).into());
|
||||
serialize_with.set(&meta.path, ser_path);
|
||||
let mut de_path = path;
|
||||
de_path
|
||||
.path
|
||||
.segments
|
||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
||||
.push(Ident::new("deserialize", de_path.span()).into());
|
||||
deserialize_with.set(&meta.path, de_path);
|
||||
}
|
||||
} else if meta.path == SERIALIZE_WITH {
|
||||
@@ -956,7 +892,12 @@ impl Variant {
|
||||
}
|
||||
|
||||
Variant {
|
||||
name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)),
|
||||
name: MultiName::from_attrs(
|
||||
Name::from(&unraw(&variant.ident)),
|
||||
ser_name,
|
||||
de_name,
|
||||
Some(de_aliases),
|
||||
),
|
||||
rename_all_rules: RenameAllRules {
|
||||
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
||||
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
||||
@@ -973,20 +914,23 @@ impl Variant {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
pub fn name(&self) -> &MultiName {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn aliases(&self) -> &BTreeSet<String> {
|
||||
pub fn aliases(&self) -> &BTreeSet<Name> {
|
||||
self.name.deserialize_aliases()
|
||||
}
|
||||
|
||||
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
|
||||
if !self.name.serialize_renamed {
|
||||
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
|
||||
self.name.serialize.value =
|
||||
rules.serialize.apply_to_variant(&self.name.serialize.value);
|
||||
}
|
||||
if !self.name.deserialize_renamed {
|
||||
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
|
||||
self.name.deserialize.value = rules
|
||||
.deserialize
|
||||
.apply_to_variant(&self.name.deserialize.value);
|
||||
}
|
||||
self.name
|
||||
.deserialize_aliases
|
||||
@@ -1032,7 +976,7 @@ impl Variant {
|
||||
|
||||
/// Represents field attribute information
|
||||
pub struct Field {
|
||||
name: Name,
|
||||
name: MultiName,
|
||||
skip_serializing: bool,
|
||||
skip_deserializing: bool,
|
||||
skip_serializing_if: Option<syn::ExprPath>,
|
||||
@@ -1074,6 +1018,7 @@ impl Field {
|
||||
field: &syn::Field,
|
||||
attrs: Option<&Variant>,
|
||||
container_default: &Default,
|
||||
private: &Ident,
|
||||
) -> Self {
|
||||
let mut ser_name = Attr::none(cx, RENAME);
|
||||
let mut de_name = Attr::none(cx, RENAME);
|
||||
@@ -1091,8 +1036,11 @@ impl Field {
|
||||
let mut flatten = BoolAttr::none(cx, FLATTEN);
|
||||
|
||||
let ident = match &field.ident {
|
||||
Some(ident) => unraw(ident),
|
||||
None => index.to_string(),
|
||||
Some(ident) => Name::from(&unraw(ident)),
|
||||
None => Name {
|
||||
value: index.to_string(),
|
||||
span: Span::call_site(),
|
||||
},
|
||||
};
|
||||
|
||||
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
|
||||
@@ -1128,15 +1076,15 @@ impl Field {
|
||||
// #[serde(rename = "foo")]
|
||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||
let (ser, de) = get_multiple_renames(cx, &meta)?;
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value));
|
||||
ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from));
|
||||
for de_value in de {
|
||||
de_name.set_if_none(de_value.value());
|
||||
de_aliases.insert(&meta.path, de_value.value());
|
||||
de_name.set_if_none(Name::from(&de_value));
|
||||
de_aliases.insert(&meta.path, Name::from(&de_value));
|
||||
}
|
||||
} else if meta.path == ALIAS {
|
||||
// #[serde(alias = "foo")]
|
||||
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
|
||||
de_aliases.insert(&meta.path, s.value());
|
||||
de_aliases.insert(&meta.path, Name::from(&s));
|
||||
}
|
||||
} else if meta.path == DEFAULT {
|
||||
if meta.input.peek(Token![=]) {
|
||||
@@ -1180,13 +1128,13 @@ impl Field {
|
||||
ser_path
|
||||
.path
|
||||
.segments
|
||||
.push(Ident::new("serialize", Span::call_site()).into());
|
||||
.push(Ident::new("serialize", ser_path.span()).into());
|
||||
serialize_with.set(&meta.path, ser_path);
|
||||
let mut de_path = path;
|
||||
de_path
|
||||
.path
|
||||
.segments
|
||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
||||
.push(Ident::new("deserialize", de_path.span()).into());
|
||||
deserialize_with.set(&meta.path, de_path);
|
||||
}
|
||||
} else if meta.path == BOUND {
|
||||
@@ -1264,7 +1212,7 @@ impl Field {
|
||||
};
|
||||
let span = Span::call_site();
|
||||
path.segments.push(Ident::new("_serde", span).into());
|
||||
path.segments.push(Ident::new("__private", span).into());
|
||||
path.segments.push(private.clone().into());
|
||||
path.segments.push(Ident::new("de", span).into());
|
||||
path.segments
|
||||
.push(Ident::new("borrow_cow_str", span).into());
|
||||
@@ -1281,7 +1229,7 @@ impl Field {
|
||||
};
|
||||
let span = Span::call_site();
|
||||
path.segments.push(Ident::new("_serde", span).into());
|
||||
path.segments.push(Ident::new("__private", span).into());
|
||||
path.segments.push(private.clone().into());
|
||||
path.segments.push(Ident::new("de", span).into());
|
||||
path.segments
|
||||
.push(Ident::new("borrow_cow_bytes", span).into());
|
||||
@@ -1299,7 +1247,7 @@ impl Field {
|
||||
}
|
||||
|
||||
Field {
|
||||
name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
|
||||
name: MultiName::from_attrs(ident, ser_name, de_name, Some(de_aliases)),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing_if: skip_serializing_if.get(),
|
||||
@@ -1315,20 +1263,22 @@ impl Field {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
pub fn name(&self) -> &MultiName {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn aliases(&self) -> &BTreeSet<String> {
|
||||
pub fn aliases(&self) -> &BTreeSet<Name> {
|
||||
self.name.deserialize_aliases()
|
||||
}
|
||||
|
||||
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
|
||||
if !self.name.serialize_renamed {
|
||||
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
|
||||
self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value);
|
||||
}
|
||||
if !self.name.deserialize_renamed {
|
||||
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
|
||||
self.name.deserialize.value = rules
|
||||
.deserialize
|
||||
.apply_to_field(&self.name.deserialize.value);
|
||||
}
|
||||
self.name
|
||||
.deserialize_aliases
|
||||
@@ -1778,7 +1728,7 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
|
||||
// attribute on the field so there must be at least one borrowable lifetime.
|
||||
fn borrowable_lifetimes(
|
||||
cx: &Ctxt,
|
||||
name: &str,
|
||||
name: &Name,
|
||||
field: &syn::Field,
|
||||
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
||||
let mut lifetimes = BTreeSet::new();
|
||||
@@ -1794,6 +1744,7 @@ fn borrowable_lifetimes(
|
||||
|
||||
fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
||||
match ty {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
syn::Type::Slice(ty) => {
|
||||
collect_lifetimes(&ty.elem, out);
|
||||
}
|
||||
@@ -1829,7 +1780,10 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
||||
syn::GenericArgument::AssocType(binding) => {
|
||||
collect_lifetimes(&binding.ty, out);
|
||||
}
|
||||
_ => {}
|
||||
syn::GenericArgument::Const(_)
|
||||
| syn::GenericArgument::AssocConst(_)
|
||||
| syn::GenericArgument::Constraint(_)
|
||||
| _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1851,7 +1805,6 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
||||
| syn::Type::Infer(_)
|
||||
| syn::Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,9 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
||||
for variant in variants {
|
||||
match variant.style {
|
||||
Style::Struct => {
|
||||
if variant.attrs.untagged() {
|
||||
continue;
|
||||
}
|
||||
for field in &variant.fields {
|
||||
let check_ser =
|
||||
!(field.attrs.skip_serializing() || variant.attrs.skip_serializing());
|
||||
@@ -326,13 +329,13 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
||||
let name = field.attrs.name();
|
||||
let ser_name = name.serialize_name();
|
||||
|
||||
if check_ser && ser_name == tag {
|
||||
if check_ser && ser_name.value == tag {
|
||||
diagnose_conflict();
|
||||
return;
|
||||
}
|
||||
|
||||
for de_name in field.attrs.aliases() {
|
||||
if check_de && de_name == tag {
|
||||
if check_de && de_name.value == tag {
|
||||
diagnose_conflict();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
pub mod name;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
use crate::internals::attr::{Attr, VecAttr};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::{self, Display};
|
||||
use syn::LitStr;
|
||||
|
||||
pub struct MultiName {
|
||||
pub(crate) serialize: Name,
|
||||
pub(crate) serialize_renamed: bool,
|
||||
pub(crate) deserialize: Name,
|
||||
pub(crate) deserialize_renamed: bool,
|
||||
pub(crate) deserialize_aliases: BTreeSet<Name>,
|
||||
}
|
||||
|
||||
impl MultiName {
|
||||
pub(crate) fn from_attrs(
|
||||
source_name: Name,
|
||||
ser_name: Attr<Name>,
|
||||
de_name: Attr<Name>,
|
||||
de_aliases: Option<VecAttr<Name>>,
|
||||
) -> Self {
|
||||
let mut alias_set = BTreeSet::new();
|
||||
if let Some(de_aliases) = de_aliases {
|
||||
for alias_name in de_aliases.get() {
|
||||
alias_set.insert(alias_name);
|
||||
}
|
||||
}
|
||||
|
||||
let ser_name = ser_name.get();
|
||||
let ser_renamed = ser_name.is_some();
|
||||
let de_name = de_name.get();
|
||||
let de_renamed = de_name.is_some();
|
||||
MultiName {
|
||||
serialize: ser_name.unwrap_or_else(|| source_name.clone()),
|
||||
serialize_renamed: ser_renamed,
|
||||
deserialize: de_name.unwrap_or(source_name),
|
||||
deserialize_renamed: de_renamed,
|
||||
deserialize_aliases: alias_set,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the container name for the container when serializing.
|
||||
pub fn serialize_name(&self) -> &Name {
|
||||
&self.serialize
|
||||
}
|
||||
|
||||
/// Return the container name for the container when deserializing.
|
||||
pub fn deserialize_name(&self) -> &Name {
|
||||
&self.deserialize
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize_aliases(&self) -> &BTreeSet<Name> {
|
||||
&self.deserialize_aliases
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Name {
|
||||
pub value: String,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl ToTokens for Name {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
LitStr::new(&self.value, self.span).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Name {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
Ord::cmp(&self.value, &other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Name {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(Ord::cmp(self, other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Name {}
|
||||
|
||||
impl PartialEq for Name {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.value == other.value
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Ident> for Name {
|
||||
fn from(ident: &Ident) -> Self {
|
||||
Name {
|
||||
value: ident.to_string(),
|
||||
span: ident.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&LitStr> for Name {
|
||||
fn from(lit: &LitStr) -> Self {
|
||||
Name {
|
||||
value: lit.value(),
|
||||
span: lit.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Name {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.value, formatter)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ use crate::internals::respan::respan;
|
||||
use proc_macro2::Span;
|
||||
use quote::ToTokens;
|
||||
use std::mem;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{
|
||||
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
|
||||
Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate,
|
||||
@@ -49,7 +48,7 @@ impl ReplaceReceiver<'_> {
|
||||
|
||||
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
|
||||
|
||||
let segments = mem::replace(&mut path.segments, Punctuated::new());
|
||||
let segments = mem::take(&mut path.segments);
|
||||
path.segments = segments.into_pairs().skip(1).collect();
|
||||
}
|
||||
|
||||
@@ -84,7 +83,7 @@ impl ReplaceReceiver<'_> {
|
||||
self.visit_type_mut_impl(ty);
|
||||
return;
|
||||
};
|
||||
*ty = self.self_ty(span).into();
|
||||
*ty = Type::Path(self.self_ty(span));
|
||||
}
|
||||
|
||||
// `Self::Assoc` -> `<Receiver>::Assoc`
|
||||
@@ -107,6 +106,7 @@ impl ReplaceReceiver<'_> {
|
||||
|
||||
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
|
||||
match ty {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
Type::Array(ty) => {
|
||||
self.visit_type_mut(&mut ty.elem);
|
||||
self.visit_expr_mut(&mut ty.len);
|
||||
@@ -147,7 +147,6 @@ impl ReplaceReceiver<'_> {
|
||||
|
||||
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -178,13 +177,13 @@ impl ReplaceReceiver<'_> {
|
||||
PathArguments::AngleBracketed(arguments) => {
|
||||
for arg in &mut arguments.args {
|
||||
match arg {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
GenericArgument::Type(arg) => self.visit_type_mut(arg),
|
||||
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
|
||||
GenericArgument::Lifetime(_)
|
||||
| GenericArgument::Const(_)
|
||||
| GenericArgument::AssocConst(_)
|
||||
| GenericArgument::Constraint(_) => {}
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -207,9 +206,11 @@ impl ReplaceReceiver<'_> {
|
||||
|
||||
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
|
||||
match bound {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
|
||||
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
TypeParamBound::Lifetime(_)
|
||||
| TypeParamBound::PreciseCapture(_)
|
||||
| TypeParamBound::Verbatim(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -228,6 +229,7 @@ impl ReplaceReceiver<'_> {
|
||||
if let Some(where_clause) = &mut generics.where_clause {
|
||||
for predicate in &mut where_clause.predicates {
|
||||
match predicate {
|
||||
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
WherePredicate::Type(predicate) => {
|
||||
self.visit_type_mut(&mut predicate.bounded_ty);
|
||||
for bound in &mut predicate.bounds {
|
||||
@@ -235,7 +237,6 @@ impl ReplaceReceiver<'_> {
|
||||
}
|
||||
}
|
||||
WherePredicate::Lifetime(_) => {}
|
||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ impl PartialEq<Symbol> for Ident {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<Symbol> for &'a Ident {
|
||||
impl PartialEq<Symbol> for &Ident {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
*self == word.0
|
||||
}
|
||||
@@ -58,7 +58,7 @@ impl PartialEq<Symbol> for Path {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<Symbol> for &'a Path {
|
||||
impl PartialEq<Symbol> for &Path {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
self.is_ident(word.0)
|
||||
}
|
||||
|
||||
+27
-2
@@ -13,7 +13,8 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.186")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.227")]
|
||||
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
||||
@@ -26,6 +27,7 @@
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||
clippy::manual_map,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::too_many_arguments,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
@@ -39,6 +41,7 @@
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::checked_conversions,
|
||||
clippy::doc_markdown,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::enum_glob_use,
|
||||
clippy::indexing_slicing,
|
||||
clippy::items_after_statements,
|
||||
@@ -50,17 +53,18 @@
|
||||
clippy::match_wildcard_for_single_variants,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::option_if_let_else,
|
||||
clippy::similar_names,
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::unused_self,
|
||||
clippy::use_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
|
||||
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
|
||||
|
||||
extern crate proc_macro2;
|
||||
extern crate quote;
|
||||
@@ -71,6 +75,8 @@ extern crate proc_macro;
|
||||
mod internals;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{ToTokens, TokenStreamExt as _};
|
||||
use syn::parse_macro_input;
|
||||
use syn::DeriveInput;
|
||||
|
||||
@@ -80,11 +86,30 @@ mod bound;
|
||||
mod fragment;
|
||||
|
||||
mod de;
|
||||
mod deprecated;
|
||||
mod dummy;
|
||||
mod pretend;
|
||||
mod ser;
|
||||
mod this;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
struct private;
|
||||
|
||||
impl private {
|
||||
fn ident(&self) -> Ident {
|
||||
Ident::new(
|
||||
concat!("__private", env!("CARGO_PKG_VERSION_PATCH")),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for private {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
tokens.append(self.ident());
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let mut input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
+16
-13
@@ -1,4 +1,5 @@
|
||||
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||
use crate::private;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
@@ -64,14 +65,14 @@ pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||
match &cont.data {
|
||||
Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
|
||||
Data::Struct(Style::Struct, fields) => {
|
||||
Data::Struct(Style::Struct | Style::Tuple | Style::Newtype, fields) => {
|
||||
if is_packed {
|
||||
pretend_fields_used_struct_packed(cont, fields)
|
||||
} else {
|
||||
pretend_fields_used_struct(cont, fields)
|
||||
}
|
||||
}
|
||||
Data::Struct(_, _) => quote!(),
|
||||
Data::Struct(Style::Unit, _) => quote!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +84,8 @@ fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream
|
||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||
match _serde::#private::None::<&#type_ident #ty_generics> {
|
||||
_serde::#private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -96,11 +97,12 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
|
||||
|
||||
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
|
||||
|
||||
let private2 = private;
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
||||
match _serde::#private::None::<&#type_ident #ty_generics> {
|
||||
_serde::#private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
||||
#(
|
||||
let _ = _serde::__private::ptr::addr_of!(__v.#members);
|
||||
let _ = _serde::#private2::ptr::addr_of!(__v.#members);
|
||||
)*
|
||||
}
|
||||
_ => {}
|
||||
@@ -115,20 +117,21 @@ fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStre
|
||||
let patterns = variants
|
||||
.iter()
|
||||
.filter_map(|variant| match variant.style {
|
||||
Style::Struct => {
|
||||
Style::Struct | Style::Tuple | Style::Newtype => {
|
||||
let variant_ident = &variant.ident;
|
||||
let members = variant.fields.iter().map(|field| &field.member);
|
||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
|
||||
}
|
||||
_ => None,
|
||||
Style::Unit => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let private2 = private;
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
match _serde::#private::None::<&#type_ident #ty_generics> {
|
||||
#(
|
||||
_serde::__private::Some(#patterns) => {}
|
||||
_serde::#private2::Some(#patterns) => {}
|
||||
)*
|
||||
_ => {}
|
||||
}
|
||||
@@ -172,8 +175,8 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
|
||||
};
|
||||
|
||||
quote! {
|
||||
match _serde::__private::None {
|
||||
_serde::__private::Some((#(#placeholders,)*)) => {
|
||||
match _serde::#private::None {
|
||||
_serde::#private::Some((#(#placeholders,)*)) => {
|
||||
let _ = #type_ident::#variant_ident #turbofish #pat;
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+71
-61
@@ -1,7 +1,9 @@
|
||||
use crate::deprecated::allow_deprecated;
|
||||
use crate::fragment::{Fragment, Match, Stmts};
|
||||
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||
use crate::internals::name::Name;
|
||||
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
|
||||
use crate::{bound, dummy, pretend, this};
|
||||
use crate::{bound, dummy, pretend, private, this};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
@@ -11,7 +13,7 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
||||
replace_receiver(input);
|
||||
|
||||
let ctxt = Ctxt::new();
|
||||
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
|
||||
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize, &private.ident()) {
|
||||
Some(cont) => cont,
|
||||
None => return Err(ctxt.check().unwrap_err()),
|
||||
};
|
||||
@@ -22,16 +24,18 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
||||
let params = Parameters::new(&cont);
|
||||
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||
let serde = cont.attrs.serde_path();
|
||||
let allow_deprecated = allow_deprecated(input);
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
let used = pretend::pretend_used(&cont, params.is_packed);
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
#allow_deprecated
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: #serde::Serializer,
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
#used
|
||||
#body
|
||||
@@ -41,10 +45,11 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
||||
} else {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
||||
#allow_deprecated
|
||||
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: #serde::Serializer,
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
#body
|
||||
}
|
||||
@@ -148,7 +153,7 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
}
|
||||
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
||||
// belong to a variant with a 'skip_serializing` or `serialize_with` attribute,
|
||||
// belong to a variant with a `skip_serializing` or `serialize_with` attribute,
|
||||
// are not serialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Serialize` bound where T is the type of the field.
|
||||
@@ -210,7 +215,7 @@ fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
|
||||
let self_var = ¶ms.self_var;
|
||||
quote_block! {
|
||||
_serde::Serialize::serialize(
|
||||
&_serde::__private::Into::<#type_into>::into(_serde::__private::Clone::clone(#self_var)),
|
||||
&_serde::#private::Into::<#type_into>::into(_serde::#private::Clone::clone(#self_var)),
|
||||
__serializer)
|
||||
}
|
||||
}
|
||||
@@ -289,9 +294,18 @@ fn serialize_tuple_struct(
|
||||
}
|
||||
|
||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(fields.len() as u64 <= u64::from(u32::max_value()));
|
||||
assert!(
|
||||
fields.len() as u64 <= u64::from(u32::MAX),
|
||||
"too many fields in {}: {}, maximum supported count is {}",
|
||||
cattrs.name().serialize_name(),
|
||||
fields.len(),
|
||||
u32::MAX,
|
||||
);
|
||||
|
||||
if cattrs.has_flatten() {
|
||||
let has_non_skipped_flatten = fields
|
||||
.iter()
|
||||
.any(|field| field.attrs.flatten() && !field.attrs.skip_serializing());
|
||||
if has_non_skipped_flatten {
|
||||
serialize_struct_as_map(params, fields, cattrs)
|
||||
} else {
|
||||
serialize_struct_as_struct(params, fields, cattrs)
|
||||
@@ -370,26 +384,8 @@ fn serialize_struct_as_map(
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||
|
||||
let len = if cattrs.has_flatten() {
|
||||
quote!(_serde::__private::None)
|
||||
} else {
|
||||
let len = serialized_fields
|
||||
.map(|field| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let field_expr = get_member(params, field, &field.member);
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(
|
||||
quote!(#tag_field_exists as usize),
|
||||
|sum, expr| quote!(#sum + #expr),
|
||||
);
|
||||
quote!(_serde::__private::Some(#len))
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?;
|
||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::#private::None)?;
|
||||
#tag_field
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
@@ -397,7 +393,7 @@ fn serialize_struct_as_map(
|
||||
}
|
||||
|
||||
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(variants.len() as u64 <= u64::from(u32::max_value()));
|
||||
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
||||
|
||||
let self_var = ¶ms.self_var;
|
||||
|
||||
@@ -411,7 +407,7 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
|
||||
|
||||
if cattrs.remote().is_some() && cattrs.non_exhaustive() {
|
||||
arms.push(quote! {
|
||||
ref unrecognized => _serde::__private::Err(_serde::ser::Error::custom(_serde::__private::ser::CannotSerializeVariant(unrecognized))),
|
||||
ref unrecognized => _serde::#private::Err(_serde::ser::Error::custom(_serde::#private::ser::CannotSerializeVariant(unrecognized))),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -438,7 +434,7 @@ fn serialize_variant(
|
||||
variant_ident
|
||||
);
|
||||
let skipped_err = quote! {
|
||||
_serde::__private::Err(_serde::ser::Error::custom(#skipped_msg))
|
||||
_serde::#private::Err(_serde::ser::Error::custom(#skipped_msg))
|
||||
};
|
||||
let fields_pat = match variant.style {
|
||||
Style::Unit => quote!(),
|
||||
@@ -592,7 +588,7 @@ fn serialize_internally_tagged_variant(
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
return quote_expr! {
|
||||
_serde::__private::ser::serialize_tagged_newtype(
|
||||
_serde::#private::ser::serialize_tagged_newtype(
|
||||
__serializer,
|
||||
#enum_ident_str,
|
||||
#variant_ident_str,
|
||||
@@ -621,7 +617,7 @@ fn serialize_internally_tagged_variant(
|
||||
}
|
||||
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> _serde::__private::ser::serialize_tagged_newtype);
|
||||
let func = quote_spanned!(span=> _serde::#private::ser::serialize_tagged_newtype);
|
||||
quote_expr! {
|
||||
#func(
|
||||
__serializer,
|
||||
@@ -655,7 +651,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
let serialize_variant = quote! {
|
||||
&_serde::__private::ser::AdjacentlyTaggedEnumVariant {
|
||||
&_serde::#private::ser::AdjacentlyTaggedEnumVariant {
|
||||
enum_name: #type_name,
|
||||
variant_index: #variant_index,
|
||||
variant_name: #variant_name,
|
||||
@@ -738,11 +734,12 @@ fn serialize_adjacently_tagged_variant(
|
||||
#[doc(hidden)]
|
||||
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
||||
data: (#(&'__a #fields_ty,)*),
|
||||
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
@@ -760,7 +757,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #content, &__AdjacentlyTagged {
|
||||
data: (#(#fields_ident,)*),
|
||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
})?;
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
}
|
||||
@@ -807,9 +804,9 @@ fn serialize_untagged_variant(
|
||||
|
||||
enum TupleVariant<'a> {
|
||||
ExternallyTagged {
|
||||
type_name: &'a str,
|
||||
type_name: &'a Name,
|
||||
variant_index: u32,
|
||||
variant_name: &'a str,
|
||||
variant_name: &'a Name,
|
||||
},
|
||||
Untagged,
|
||||
}
|
||||
@@ -876,11 +873,11 @@ fn serialize_tuple_variant(
|
||||
enum StructVariant<'a> {
|
||||
ExternallyTagged {
|
||||
variant_index: u32,
|
||||
variant_name: &'a str,
|
||||
variant_name: &'a Name,
|
||||
},
|
||||
InternallyTagged {
|
||||
tag: &'a str,
|
||||
variant_name: &'a str,
|
||||
variant_name: &'a Name,
|
||||
},
|
||||
Untagged,
|
||||
}
|
||||
@@ -889,7 +886,7 @@ fn serialize_struct_variant(
|
||||
context: StructVariant,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
name: &Name,
|
||||
) -> Fragment {
|
||||
if fields.iter().any(|field| field.attrs.flatten()) {
|
||||
return serialize_struct_variant_with_flatten(context, params, fields, name);
|
||||
@@ -973,7 +970,7 @@ fn serialize_struct_variant_with_flatten(
|
||||
context: StructVariant,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
name: &Name,
|
||||
) -> Fragment {
|
||||
let struct_trait = StructTrait::SerializeMap;
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
|
||||
@@ -1002,18 +999,19 @@ fn serialize_struct_variant_with_flatten(
|
||||
#[doc(hidden)]
|
||||
struct __EnumFlatten #wrapper_generics #where_clause {
|
||||
data: (#(&'__a #fields_ty,)*),
|
||||
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
let (#(#members,)*) = self.data;
|
||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::__private::None)?;
|
||||
_serde::#private::None)?;
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
@@ -1026,7 +1024,7 @@ fn serialize_struct_variant_with_flatten(
|
||||
#variant_name,
|
||||
&__EnumFlatten {
|
||||
data: (#(#members,)*),
|
||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1034,7 +1032,7 @@ fn serialize_struct_variant_with_flatten(
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::__private::None)?;
|
||||
_serde::#private::None)?;
|
||||
_serde::ser::SerializeMap::serialize_entry(
|
||||
&mut __serde_state,
|
||||
#tag,
|
||||
@@ -1048,7 +1046,7 @@ fn serialize_struct_variant_with_flatten(
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::__private::None)?;
|
||||
_serde::#private::None)?;
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
@@ -1137,7 +1135,7 @@ fn serialize_struct_visitor(
|
||||
let ser = if field.attrs.flatten() {
|
||||
let func = quote_spanned!(span=> _serde::Serialize::serialize);
|
||||
quote! {
|
||||
#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))?;
|
||||
#func(&#field_expr, _serde::#private::ser::FlatMapSerializer(&mut __serde_state))?;
|
||||
}
|
||||
} else {
|
||||
let func = struct_trait.serialize_field(span);
|
||||
@@ -1229,25 +1227,37 @@ fn wrap_serialize_with(
|
||||
})
|
||||
});
|
||||
|
||||
quote!({
|
||||
let self_var = quote!(self);
|
||||
let serializer_var = quote!(__s);
|
||||
|
||||
// If #serialize_with returns wrong type, error will be reported on here.
|
||||
// We attach span of the path to this piece so error will be reported
|
||||
// on the #[serde(with = "...")]
|
||||
// ^^^^^
|
||||
let wrapper_serialize = quote_spanned! {serialize_with.span()=>
|
||||
#serialize_with(#(#self_var.values.#field_access, )* #serializer_var)
|
||||
};
|
||||
|
||||
quote!(&{
|
||||
#[doc(hidden)]
|
||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||
values: (#(&'__a #field_tys, )*),
|
||||
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData<#this_type #ty_generics>,
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __s: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
|
||||
fn serialize<__S>(&#self_var, #serializer_var: __S) -> _serde::#private::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
#serialize_with(#(self.values.#field_access, )* __s)
|
||||
#wrapper_serialize
|
||||
}
|
||||
}
|
||||
|
||||
&__SerializeWith {
|
||||
__SerializeWith {
|
||||
values: (#(#field_exprs, )*),
|
||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
||||
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1283,11 +1293,11 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea
|
||||
quote!(&#self_var.#member)
|
||||
};
|
||||
let ty = field.ty;
|
||||
quote!(_serde::__private::ser::constrain::<#ty>(#inner))
|
||||
quote!(_serde::#private::ser::constrain::<#ty>(#inner))
|
||||
}
|
||||
(true, Some(getter)) => {
|
||||
let ty = field.ty;
|
||||
quote!(_serde::__private::ser::constrain::<#ty>(&#getter(#self_var)))
|
||||
quote!(_serde::#private::ser::constrain::<#ty>(&#getter(#self_var)))
|
||||
}
|
||||
(false, Some(_)) => {
|
||||
unreachable!("getter is only allowed for remote impls");
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.28.0" # remember to update html_root_url
|
||||
version = "0.29.1"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
description = "AST representation used by Serde derive macros. Unstable."
|
||||
documentation = "https://docs.rs/serde_derive_internals"
|
||||
edition = "2021"
|
||||
exclude = ["build.rs"]
|
||||
homepage = "https://serde.rs"
|
||||
keywords = ["serde", "serialization"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.61"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "2.0.28", default-features = false, features = ["clone-impls", "derive", "parsing", "printing"] }
|
||||
proc-macro2 = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
rustdoc-args = [
|
||||
"--generate-link-to-definition",
|
||||
"--generate-macro-expansion",
|
||||
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
|
||||
]
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
// Warning: build.rs is not published to crates.io.
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=src/mod.rs");
|
||||
|
||||
println!("cargo:rustc-cfg=check_cfg");
|
||||
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
|
||||
println!("cargo:rustc-check-cfg=cfg(exhaustive)");
|
||||
println!("cargo:rustc-check-cfg=cfg(serde_build_from_git)");
|
||||
println!("cargo:rustc-check-cfg=cfg(feature, values(\"deserialize_in_place\"))");
|
||||
|
||||
// Sometimes on Windows the git checkout does not correctly wire up the
|
||||
// symlink from serde_derive_internals/src to serde_derive/src/internals.
|
||||
// When this happens we'll just build based on relative paths within the git
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.29.1")]
|
||||
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
@@ -8,6 +9,7 @@
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||
clippy::manual_map,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::redundant_field_names,
|
||||
clippy::result_unit_err,
|
||||
clippy::should_implement_trait,
|
||||
@@ -19,6 +21,7 @@
|
||||
// Ignored clippy_pedantic lints
|
||||
#![allow(
|
||||
clippy::doc_markdown,
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::enum_glob_use,
|
||||
clippy::items_after_statements,
|
||||
clippy::let_underscore_untyped,
|
||||
@@ -34,9 +37,11 @@
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::uninlined_format_args,
|
||||
clippy::unused_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
|
||||
|
||||
extern crate proc_macro2;
|
||||
extern crate quote;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "serde_test_suite"
|
||||
version = "0.0.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
@@ -13,9 +13,9 @@ serde = { path = "../serde" }
|
||||
|
||||
[dev-dependencies]
|
||||
automod = "1.0.1"
|
||||
fnv = "1.0"
|
||||
foldhash = "0.2"
|
||||
rustversion = "1.0"
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||
serde_test = "1.0.176"
|
||||
trybuild = { version = "1.0.66", features = ["diff"] }
|
||||
trybuild = { version = "1.0.108", features = ["diff"] }
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/target/
|
||||
/Cargo.lock
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "serde_derive_tests_no_std"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
@@ -10,4 +10,10 @@ libc = { version = "0.2", default-features = false }
|
||||
serde = { path = "../../serde", default-features = false }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(lang_items, start)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[start]
|
||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
use core::ffi::c_int;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality() {}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe {
|
||||
@@ -23,21 +20,21 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Unit;
|
||||
pub struct Unit;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Newtype(u8);
|
||||
pub struct Newtype(u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Tuple(u8, u8);
|
||||
pub struct Tuple(u8, u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Struct {
|
||||
pub struct Struct {
|
||||
f: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum Enum {
|
||||
pub enum Enum {
|
||||
Unit,
|
||||
Newtype(u8),
|
||||
Tuple(u8, u8),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[rustversion::attr(not(nightly), ignore)]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
#[cfg_attr(target_os = "emscripten", ignore = "disabled on Emscripten")]
|
||||
#[rustversion::attr(not(nightly), ignore = "requires nightly")]
|
||||
#[cfg_attr(miri, ignore = "incompatible with miri")]
|
||||
#[allow(unused_attributes)]
|
||||
#[test]
|
||||
fn ui() {
|
||||
|
||||
@@ -34,9 +34,8 @@ macro_rules! hashset {
|
||||
$(set.insert($value);)+
|
||||
set
|
||||
}};
|
||||
($hasher:ident @ $($value:expr),+) => {{
|
||||
use std::hash::BuildHasherDefault;
|
||||
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||
($hasher:ty; $($value:expr),+) => {{
|
||||
let mut set = HashSet::<_, $hasher>::default();
|
||||
$(set.insert($value);)+
|
||||
set
|
||||
}};
|
||||
@@ -51,9 +50,8 @@ macro_rules! hashmap {
|
||||
$(map.insert($key, $value);)+
|
||||
map
|
||||
}};
|
||||
($hasher:ident @ $($key:expr => $value:expr),+) => {{
|
||||
use std::hash::BuildHasherDefault;
|
||||
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||
($hasher:ty; $($key:expr => $value:expr),+) => {{
|
||||
let mut map = HashMap::<_, _, $hasher>::default();
|
||||
$(map.insert($key, $value);)+
|
||||
map
|
||||
}};
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#![allow(dead_code)] // we do not read enum fields
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Nested;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub enum ExternallyTagged1 {
|
||||
Tuple(f64, String),
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub enum ExternallyTagged2 {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
Tuple(f64, String),
|
||||
}
|
||||
|
||||
// Internally tagged enums cannot contain tuple variants so not tested here
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "tag", content = "content")]
|
||||
pub enum AdjacentlyTagged1 {
|
||||
Tuple(f64, String),
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "tag", content = "content")]
|
||||
pub enum AdjacentlyTagged2 {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
Tuple(f64, String),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Untagged1 {
|
||||
Tuple(f64, String),
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Untagged2 {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
nested: Nested,
|
||||
},
|
||||
Tuple(f64, String),
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -7,7 +9,9 @@ pub struct Nested;
|
||||
pub enum ExternallyTagged {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
#[allow(dead_code)]
|
||||
nested: Nested,
|
||||
#[allow(dead_code)]
|
||||
string: &'static str,
|
||||
},
|
||||
}
|
||||
@@ -17,7 +21,9 @@ pub enum ExternallyTagged {
|
||||
pub enum InternallyTagged {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
#[allow(dead_code)]
|
||||
nested: Nested,
|
||||
#[allow(dead_code)]
|
||||
string: &'static str,
|
||||
},
|
||||
}
|
||||
@@ -27,7 +33,9 @@ pub enum InternallyTagged {
|
||||
pub enum AdjacentlyTagged {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
#[allow(dead_code)]
|
||||
nested: Nested,
|
||||
#[allow(dead_code)]
|
||||
string: &'static str,
|
||||
},
|
||||
}
|
||||
@@ -37,7 +45,9 @@ pub enum AdjacentlyTagged {
|
||||
pub enum UntaggedWorkaround {
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
#[allow(dead_code)]
|
||||
nested: Nested,
|
||||
#[allow(dead_code)]
|
||||
string: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
macro_rules! bug {
|
||||
|
||||
@@ -2,4 +2,5 @@ use serde_derive::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde()]
|
||||
#[allow(dead_code)]
|
||||
pub struct S;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
enum Enum {
|
||||
Simple {
|
||||
a: i32,
|
||||
},
|
||||
Flatten {
|
||||
#[serde(flatten)]
|
||||
flatten: (),
|
||||
a: i32,
|
||||
},
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_variant() {
|
||||
assert_tokens(
|
||||
&Enum::Simple { a: 42 },
|
||||
&[
|
||||
Token::StructVariant {
|
||||
name: "Enum",
|
||||
variant: "Simple",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("a"),
|
||||
Token::I32(42),
|
||||
Token::StructVariantEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flatten_variant() {
|
||||
assert_tokens(
|
||||
&Enum::Flatten { flatten: (), a: 42 },
|
||||
&[
|
||||
Token::NewtypeVariant {
|
||||
name: "Enum",
|
||||
variant: "Flatten",
|
||||
},
|
||||
Token::Map { len: None },
|
||||
Token::Str("a"),
|
||||
Token::I32(42),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#![allow(dead_code)] // we do not read enum fields
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum A {
|
||||
B {
|
||||
c: String,
|
||||
},
|
||||
D {
|
||||
#[serde(flatten)]
|
||||
e: E,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct E {}
|
||||
@@ -0,0 +1,33 @@
|
||||
#![allow(clippy::trivially_copy_pass_by_ref, dead_code)]
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
macro_rules! declare_in_macro {
|
||||
($with:literal) => {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct S {
|
||||
#[serde(with = $with)]
|
||||
f: i32,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare_in_macro!("with");
|
||||
|
||||
mod with {
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S>(_: &i32, _: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D>(_: D) -> Result<i32, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#![allow(clippy::trivially_copy_pass_by_ref, dead_code)]
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
macro_rules! declare_in_macro {
|
||||
($with:literal) => {
|
||||
#[derive(Deserialize)]
|
||||
pub struct S(
|
||||
#[serde(with = $with)]
|
||||
#[allow(dead_code)]
|
||||
i32,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
declare_in_macro!("with");
|
||||
|
||||
mod with {
|
||||
use serde::Deserializer;
|
||||
|
||||
pub fn deserialize<'de, D>(_: D) -> Result<i32, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
+1373
-969
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
||||
#![allow(
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::items_after_statements,
|
||||
clippy::used_underscore_binding
|
||||
clippy::used_underscore_binding,
|
||||
// We use lots of declarations inside function bodies to avoid conflicts,
|
||||
// but they aren't used. We just want to make sure they compile.
|
||||
dead_code,
|
||||
)]
|
||||
|
||||
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
|
||||
@@ -162,7 +165,7 @@ fn test_cow() {
|
||||
#[test]
|
||||
fn test_lifetimes() {
|
||||
#[derive(Deserialize)]
|
||||
struct Cows<'a, 'b> {
|
||||
pub struct Cows<'a, 'b> {
|
||||
_copied: Cow<'a, str>,
|
||||
|
||||
#[serde(borrow)]
|
||||
@@ -178,7 +181,7 @@ fn test_lifetimes() {
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Wrap<'a, 'b> {
|
||||
pub struct Wrap<'a, 'b> {
|
||||
#[serde(borrow = "'b")]
|
||||
_cows: Cows<'a, 'b>,
|
||||
}
|
||||
|
||||
+102
-5
@@ -10,7 +10,7 @@
|
||||
)]
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
|
||||
use fnv::FnvHasher;
|
||||
use serde::de::value::{F32Deserializer, F64Deserializer};
|
||||
use serde::de::{Deserialize, DeserializeOwned, Deserializer, IntoDeserializer};
|
||||
use serde_derive::Deserialize;
|
||||
use serde_test::{assert_de_tokens, Configure, Token};
|
||||
@@ -22,7 +22,7 @@ use std::iter;
|
||||
use std::net;
|
||||
use std::num::{
|
||||
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
|
||||
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
|
||||
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Saturating, Wrapping,
|
||||
};
|
||||
use std::ops::Bound;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -92,7 +92,7 @@ struct StructSkipDefault {
|
||||
|
||||
#[derive(PartialEq, Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
struct StructSkipDefaultGeneric<T> {
|
||||
pub struct StructSkipDefaultGeneric<T> {
|
||||
#[serde(skip_deserializing)]
|
||||
t: T,
|
||||
}
|
||||
@@ -832,6 +832,26 @@ fn test_f64() {
|
||||
test(1.11, &[Token::F64(1.11)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
let f32_deserializer = F32Deserializer::<serde::de::value::Error>::new;
|
||||
let f64_deserializer = F64Deserializer::<serde::de::value::Error>::new;
|
||||
|
||||
let pos_f32_nan = f32_deserializer(f32::NAN.copysign(1.0));
|
||||
let pos_f64_nan = f64_deserializer(f64::NAN.copysign(1.0));
|
||||
assert!(f32::deserialize(pos_f32_nan).unwrap().is_sign_positive());
|
||||
assert!(f32::deserialize(pos_f64_nan).unwrap().is_sign_positive());
|
||||
assert!(f64::deserialize(pos_f32_nan).unwrap().is_sign_positive());
|
||||
assert!(f64::deserialize(pos_f64_nan).unwrap().is_sign_positive());
|
||||
|
||||
let neg_f32_nan = f32_deserializer(f32::NAN.copysign(-1.0));
|
||||
let neg_f64_nan = f64_deserializer(f64::NAN.copysign(-1.0));
|
||||
assert!(f32::deserialize(neg_f32_nan).unwrap().is_sign_negative());
|
||||
assert!(f32::deserialize(neg_f64_nan).unwrap().is_sign_negative());
|
||||
assert!(f64::deserialize(neg_f32_nan).unwrap().is_sign_negative());
|
||||
assert!(f64::deserialize(neg_f64_nan).unwrap().is_sign_negative());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_char() {
|
||||
test('a', &[Token::Char('a')]);
|
||||
@@ -1019,7 +1039,7 @@ fn test_hashset() {
|
||||
],
|
||||
);
|
||||
test(
|
||||
hashset![FnvHasher @ 1, 2, 3],
|
||||
hashset![foldhash::fast::FixedState; 1, 2, 3],
|
||||
&[
|
||||
Token::Seq { len: Some(3) },
|
||||
Token::I32(1),
|
||||
@@ -1254,7 +1274,7 @@ fn test_hashmap() {
|
||||
],
|
||||
);
|
||||
test(
|
||||
hashmap![FnvHasher @ 1 => 2, 3 => 4],
|
||||
hashmap![foldhash::fast::FixedState; 1 => 2, 3 => 4],
|
||||
&[
|
||||
Token::Map { len: Some(2) },
|
||||
Token::I32(1),
|
||||
@@ -1877,6 +1897,46 @@ fn test_range_inclusive() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_from() {
|
||||
test(
|
||||
1u32..,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "RangeFrom",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("start"),
|
||||
Token::U32(1),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
test(
|
||||
1u32..,
|
||||
&[Token::Seq { len: Some(1) }, Token::U32(1), Token::SeqEnd],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_to() {
|
||||
test(
|
||||
..2u32,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "RangeTo",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("end"),
|
||||
Token::U32(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
test(
|
||||
..2u32,
|
||||
&[Token::Seq { len: Some(1) }, Token::U32(2), Token::SeqEnd],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound() {
|
||||
test(
|
||||
@@ -2004,6 +2064,43 @@ fn test_wrapping() {
|
||||
test(Wrapping(1usize), &[Token::U64(1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_saturating() {
|
||||
test(Saturating(1usize), &[Token::U32(1)]);
|
||||
test(Saturating(1usize), &[Token::U64(1)]);
|
||||
test(Saturating(0u8), &[Token::I8(0)]);
|
||||
test(Saturating(0u16), &[Token::I16(0)]);
|
||||
|
||||
// saturate input values at the minimum or maximum value
|
||||
test(Saturating(u8::MAX), &[Token::U16(u16::MAX)]);
|
||||
test(Saturating(u8::MAX), &[Token::U16(u8::MAX as u16 + 1)]);
|
||||
test(Saturating(u16::MAX), &[Token::U32(u32::MAX)]);
|
||||
test(Saturating(u32::MAX), &[Token::U64(u64::MAX)]);
|
||||
test(Saturating(u8::MIN), &[Token::I8(i8::MIN)]);
|
||||
test(Saturating(u16::MIN), &[Token::I16(i16::MIN)]);
|
||||
test(Saturating(u32::MIN), &[Token::I32(i32::MIN)]);
|
||||
test(Saturating(i8::MIN), &[Token::I16(i16::MIN)]);
|
||||
test(Saturating(i16::MIN), &[Token::I32(i32::MIN)]);
|
||||
test(Saturating(i32::MIN), &[Token::I64(i64::MIN)]);
|
||||
|
||||
test(Saturating(u8::MIN), &[Token::I8(-1)]);
|
||||
test(Saturating(u16::MIN), &[Token::I16(-1)]);
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
{
|
||||
test(Saturating(usize::MIN), &[Token::U64(u64::MIN)]);
|
||||
test(Saturating(usize::MAX), &[Token::U64(u64::MAX)]);
|
||||
test(Saturating(isize::MIN), &[Token::I64(i64::MIN)]);
|
||||
test(Saturating(isize::MAX), &[Token::I64(i64::MAX)]);
|
||||
test(Saturating(0usize), &[Token::I64(i64::MIN)]);
|
||||
|
||||
test(
|
||||
Saturating(9_223_372_036_854_775_807usize),
|
||||
&[Token::I64(i64::MAX)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rc_dst() {
|
||||
test(Rc::<str>::from("s"), &[Token::Str("s")]);
|
||||
|
||||
@@ -1434,7 +1434,15 @@ fn test_number_from_string() {
|
||||
fn test_integer_from_float() {
|
||||
assert_de_tokens_error::<isize>(
|
||||
&[Token::F32(0.0)],
|
||||
"invalid type: floating point `0`, expected isize",
|
||||
"invalid type: floating point `0.0`, expected isize",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan_no_decimal_point() {
|
||||
assert_de_tokens_error::<isize>(
|
||||
&[Token::F32(f32::NAN)],
|
||||
"invalid type: floating point `NaN`, expected isize",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1459,7 +1467,7 @@ fn test_duration_overflow_seq() {
|
||||
assert_de_tokens_error::<Duration>(
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U64(u64::MAX),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
@@ -1476,7 +1484,7 @@ fn test_duration_overflow_struct() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("secs"),
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U64(u64::MAX),
|
||||
Token::Str("nanos"),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::StructEnd,
|
||||
@@ -1490,7 +1498,7 @@ fn test_systemtime_overflow_seq() {
|
||||
assert_de_tokens_error::<SystemTime>(
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U64(u64::MAX),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
@@ -1507,7 +1515,7 @@ fn test_systemtime_overflow_struct() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("secs_since_epoch"),
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U64(u64::MAX),
|
||||
Token::Str("nanos_since_epoch"),
|
||||
Token::U32(1_000_000_000),
|
||||
Token::StructEnd,
|
||||
@@ -1516,13 +1524,12 @@ fn test_systemtime_overflow_struct() {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(systemtime_checked_add)]
|
||||
#[test]
|
||||
fn test_systemtime_overflow() {
|
||||
assert_de_tokens_error::<SystemTime>(
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::U64(u64::max_value()),
|
||||
Token::U64(u64::MAX),
|
||||
Token::U32(0),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#![deny(deprecated)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[deprecated]
|
||||
enum DeprecatedEnum {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[deprecated]
|
||||
struct DeprecatedStruct {
|
||||
a: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum DeprecatedVariant {
|
||||
A,
|
||||
#[deprecated]
|
||||
B,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct DeprecatedField {
|
||||
#[deprecated]
|
||||
a: bool,
|
||||
}
|
||||
@@ -0,0 +1,799 @@
|
||||
#![deny(trivial_numeric_casts)]
|
||||
#![allow(
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::enum_variant_names,
|
||||
clippy::redundant_field_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum AdjacentlyTagged<T> {
|
||||
Unit,
|
||||
Newtype(T),
|
||||
Tuple(u8, u8),
|
||||
Struct { f: u8 },
|
||||
}
|
||||
|
||||
mod unit {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map_str_tag_only() {
|
||||
// Map: tag only
|
||||
assert_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: tag only and incorrect hint for number of elements
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_int_tag_only() {
|
||||
// Map: tag (as number) only
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::U16(0),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_bytes_tag_only() {
|
||||
// Map: tag only
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Bytes(b"t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: tag only
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::BorrowedBytes(b"t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_str_tag_content() {
|
||||
// Map: tag + content
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
// Map: content + tag
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: tag + content + excess fields (f, g, h)
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("f"),
|
||||
Token::Unit,
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("g"),
|
||||
Token::Unit,
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("h"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_int_tag_content() {
|
||||
// Map: tag (as number) + content (as number)
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::U8(0),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::U8(1),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: content (as number) + tag (as number)
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::U64(1),
|
||||
Token::Unit,
|
||||
Token::U64(0),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_bytes_tag_content() {
|
||||
// Map: tag + content
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::BorrowedBytes(b"t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::BorrowedBytes(b"c"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: content + tag
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Bytes(b"c"),
|
||||
Token::Unit,
|
||||
Token::Bytes(b"t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq_tag_content() {
|
||||
// Seq: tag and content
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Unit,
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Seq: tag (as string) and content
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Seq { len: None },
|
||||
Token::Str("Unit"), // tag
|
||||
Token::Unit, // content
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Seq: tag (as borrowed string) and content
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit::<u8>,
|
||||
&[
|
||||
Token::Seq { len: None },
|
||||
Token::BorrowedStr("Unit"), // tag
|
||||
Token::Unit, // content
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod newtype {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map_tag_only() {
|
||||
// optional newtype with no content field
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Newtype::<Option<u8>>(None),
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_tag_content() {
|
||||
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||
|
||||
// Map: tag + content
|
||||
assert_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: content + tag
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::U8(1),
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq() {
|
||||
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||
|
||||
// Seq: tag and content
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::U8(1),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Seq: tag (as string) and content
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Seq { len: None },
|
||||
Token::Str("Newtype"), // tag
|
||||
Token::U8(1), // content
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Seq: tag (as borrowed string) and content
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Seq { len: None },
|
||||
Token::BorrowedStr("Newtype"), // tag
|
||||
Token::U8(1), // content
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_with_newtype() {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct NewtypeStruct(u32);
|
||||
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Newtype(NewtypeStruct(5)),
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::NewtypeStruct {
|
||||
name: "NewtypeStruct",
|
||||
},
|
||||
Token::U32(5),
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
mod tuple {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map() {
|
||||
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||
|
||||
// Map: tag + content
|
||||
assert_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Tuple",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Tuple { len: 2 },
|
||||
Token::U8(1),
|
||||
Token::U8(1),
|
||||
Token::TupleEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: content + tag
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Tuple { len: 2 },
|
||||
Token::U8(1),
|
||||
Token::U8(1),
|
||||
Token::TupleEnd,
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Tuple",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq() {
|
||||
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||
|
||||
// Seq: tag + content
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Tuple",
|
||||
},
|
||||
Token::Tuple { len: 2 },
|
||||
Token::U8(1),
|
||||
Token::U8(1),
|
||||
Token::TupleEnd,
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod struct_ {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map() {
|
||||
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||
|
||||
// Map: tag + content
|
||||
assert_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Struct {
|
||||
name: "Struct",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("f"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Map: content + tag
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Struct {
|
||||
name: "Struct",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("f"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seq() {
|
||||
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||
|
||||
// Seq: tag + content
|
||||
assert_de_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::Seq { len: Some(2) },
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::Struct {
|
||||
name: "Struct",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("f"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_with_flatten() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum Data {
|
||||
A {
|
||||
a: i32,
|
||||
#[serde(flatten)]
|
||||
flat: Flat,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct Flat {
|
||||
b: i32,
|
||||
}
|
||||
|
||||
let data = Data::A {
|
||||
a: 0,
|
||||
flat: Flat { b: 0 },
|
||||
};
|
||||
|
||||
assert_tokens(
|
||||
&data,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Data",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "Data",
|
||||
variant: "A",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Map { len: None },
|
||||
Token::Str("a"),
|
||||
Token::I32(0),
|
||||
Token::Str("b"),
|
||||
Token::I32(0),
|
||||
Token::MapEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expecting_message() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "tag", content = "content")]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
AdjacentlyTagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Str("AdjacentlyTagged")],
|
||||
r#"invalid type: string "AdjacentlyTagged", expected something strange..."#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Unit],
|
||||
r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#,
|
||||
);
|
||||
|
||||
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
|
||||
"invalid type: unit value, expected variant of enum Enum",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partially_untagged() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum Data {
|
||||
A(u32),
|
||||
B,
|
||||
#[serde(untagged)]
|
||||
Var(u32),
|
||||
}
|
||||
|
||||
let data = Data::A(7);
|
||||
|
||||
assert_de_tokens(
|
||||
&data,
|
||||
&[
|
||||
Token::Map { len: None },
|
||||
Token::Str("t"),
|
||||
Token::Str("A"),
|
||||
Token::Str("c"),
|
||||
Token::U32(7),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
|
||||
let data = Data::Var(42);
|
||||
|
||||
assert_de_tokens(&data, &[Token::U32(42)]);
|
||||
|
||||
// TODO test error output
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deny_unknown_fields() {
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(tag = "t", content = "c", deny_unknown_fields)]
|
||||
enum AdjacentlyTagged {
|
||||
Unit,
|
||||
}
|
||||
|
||||
assert_de_tokens(
|
||||
&AdjacentlyTagged::Unit,
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("h"),
|
||||
],
|
||||
r#"invalid value: string "h", expected "t" or "c""#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("h"),
|
||||
],
|
||||
r#"invalid value: string "h", expected "t" or "c""#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("h"),
|
||||
],
|
||||
r#"invalid value: string "h", expected "t" or "c""#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::U64(0), // tag field
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::U64(3),
|
||||
],
|
||||
r#"invalid value: integer `3`, expected "t" or "c""#,
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "AdjacentlyTagged",
|
||||
len: 2,
|
||||
},
|
||||
Token::Bytes(b"c"),
|
||||
Token::Unit,
|
||||
Token::Bytes(b"h"),
|
||||
],
|
||||
r#"invalid value: byte array, expected "t" or "c""#,
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,583 @@
|
||||
#![deny(trivial_numeric_casts)]
|
||||
#![allow(
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::enum_variant_names,
|
||||
clippy::redundant_field_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
mod bytes;
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn complex() {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Untagged {
|
||||
A { a: u8 },
|
||||
B { b: u8 },
|
||||
C,
|
||||
D(u8),
|
||||
E(String),
|
||||
F(u8, u8),
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
&Untagged::A { a: 1 },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("a"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
&Untagged::B { b: 2 },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("b"),
|
||||
Token::U8(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
// Serializes to unit, deserializes from either depending on format's
|
||||
// preference.
|
||||
assert_tokens(&Untagged::C, &[Token::Unit]);
|
||||
assert_de_tokens(&Untagged::C, &[Token::None]);
|
||||
|
||||
assert_tokens(&Untagged::D(4), &[Token::U8(4)]);
|
||||
assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]);
|
||||
|
||||
assert_tokens(
|
||||
&Untagged::F(1, 2),
|
||||
&[
|
||||
Token::Tuple { len: 2 },
|
||||
Token::U8(1),
|
||||
Token::U8(2),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Untagged>(
|
||||
&[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd],
|
||||
"data did not match any variant of untagged enum Untagged",
|
||||
);
|
||||
|
||||
assert_de_tokens_error::<Untagged>(
|
||||
&[
|
||||
Token::Tuple { len: 3 },
|
||||
Token::U8(1),
|
||||
Token::U8(2),
|
||||
Token::U8(3),
|
||||
Token::TupleEnd,
|
||||
],
|
||||
"data did not match any variant of untagged enum Untagged",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn newtype_unit_and_empty_map() {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct Unit;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Message {
|
||||
Unit(Unit),
|
||||
Map(BTreeMap<String, String>),
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
&Message::Map(BTreeMap::new()),
|
||||
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_newtype_struct
|
||||
#[test]
|
||||
fn newtype_struct() {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct NewtypeStruct(u32);
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum E {
|
||||
Newtype(NewtypeStruct),
|
||||
Null,
|
||||
}
|
||||
|
||||
let value = E::Newtype(NewtypeStruct(5));
|
||||
|
||||
// Content::Newtype case
|
||||
assert_tokens(
|
||||
&value,
|
||||
&[
|
||||
Token::NewtypeStruct {
|
||||
name: "NewtypeStruct",
|
||||
},
|
||||
Token::U32(5),
|
||||
],
|
||||
);
|
||||
|
||||
// _ case
|
||||
assert_de_tokens(&value, &[Token::U32(5)]);
|
||||
}
|
||||
|
||||
mod newtype_enum {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Outer {
|
||||
Inner(Inner),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
enum Inner {
|
||||
Unit,
|
||||
Newtype(u8),
|
||||
Tuple0(),
|
||||
Tuple2(u8, u8),
|
||||
Struct { f: u8 },
|
||||
EmptyStruct {},
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::unit_variant
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert_tokens(
|
||||
&Outer::Inner(Inner::Unit),
|
||||
&[Token::UnitVariant {
|
||||
name: "Inner",
|
||||
variant: "Unit",
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::newtype_variant_seed
|
||||
#[test]
|
||||
fn newtype() {
|
||||
assert_tokens(
|
||||
&Outer::Inner(Inner::Newtype(1)),
|
||||
&[
|
||||
Token::NewtypeVariant {
|
||||
name: "Inner",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::U8(1),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||
#[test]
|
||||
fn tuple0() {
|
||||
assert_tokens(
|
||||
&Outer::Inner(Inner::Tuple0()),
|
||||
&[
|
||||
Token::TupleVariant {
|
||||
name: "Inner",
|
||||
variant: "Tuple0",
|
||||
len: 0,
|
||||
},
|
||||
Token::TupleVariantEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||
#[test]
|
||||
fn tuple2() {
|
||||
assert_tokens(
|
||||
&Outer::Inner(Inner::Tuple2(1, 1)),
|
||||
&[
|
||||
Token::TupleVariant {
|
||||
name: "Inner",
|
||||
variant: "Tuple2",
|
||||
len: 2,
|
||||
},
|
||||
Token::U8(1),
|
||||
Token::U8(1),
|
||||
Token::TupleVariantEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||
// Content::Map case
|
||||
#[test]
|
||||
fn struct_from_map() {
|
||||
assert_tokens(
|
||||
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||
&[
|
||||
Token::StructVariant {
|
||||
name: "Inner",
|
||||
variant: "Struct",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("f"),
|
||||
Token::U8(1),
|
||||
Token::StructVariantEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||
// Content::Seq case
|
||||
#[test]
|
||||
fn struct_from_seq() {
|
||||
assert_de_tokens(
|
||||
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
// tag
|
||||
Token::Str("Struct"),
|
||||
// content
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::U8(1),
|
||||
Token::SeqEnd,
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||
// Content::Map case
|
||||
// Special case - empty map
|
||||
#[test]
|
||||
fn empty_struct_from_map() {
|
||||
assert_de_tokens(
|
||||
&Outer::Inner(Inner::EmptyStruct {}),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
// tag
|
||||
Token::Str("EmptyStruct"),
|
||||
// content
|
||||
Token::Map { len: Some(0) },
|
||||
Token::MapEnd,
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||
// Content::Seq case
|
||||
// Special case - empty seq
|
||||
#[test]
|
||||
fn empty_struct_from_seq() {
|
||||
assert_de_tokens(
|
||||
&Outer::Inner(Inner::EmptyStruct {}),
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
// tag
|
||||
Token::Str("EmptyStruct"),
|
||||
// content
|
||||
Token::Seq { len: Some(0) },
|
||||
Token::SeqEnd,
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_option
|
||||
mod with_optional_field {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Enum {
|
||||
Struct { optional: Option<u32> },
|
||||
Null,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn some() {
|
||||
assert_tokens(
|
||||
&Enum::Struct { optional: Some(42) },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Enum",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("optional"),
|
||||
Token::Some,
|
||||
Token::U32(42),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn some_without_marker() {
|
||||
assert_de_tokens(
|
||||
&Enum::Struct { optional: Some(42) },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Enum",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("optional"),
|
||||
Token::U32(42),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn none() {
|
||||
assert_tokens(
|
||||
&Enum::Struct { optional: None },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Enum",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("optional"),
|
||||
Token::None,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert_de_tokens(
|
||||
&Enum::Struct { optional: None },
|
||||
&[
|
||||
Token::Map { len: None },
|
||||
Token::Str("optional"),
|
||||
Token::Unit,
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_and_bytes() {
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Untagged {
|
||||
String {
|
||||
string: String,
|
||||
},
|
||||
Bytes {
|
||||
#[serde(with = "bytes")]
|
||||
bytes: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::String {
|
||||
string: "\0".to_owned(),
|
||||
},
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("string"),
|
||||
Token::Str("\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::String {
|
||||
string: "\0".to_owned(),
|
||||
},
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("string"),
|
||||
Token::String("\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::String {
|
||||
string: "\0".to_owned(),
|
||||
},
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("string"),
|
||||
Token::Bytes(b"\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::String {
|
||||
string: "\0".to_owned(),
|
||||
},
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("string"),
|
||||
Token::ByteBuf(b"\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::Bytes { bytes: vec![0] },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("bytes"),
|
||||
Token::Str("\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::Bytes { bytes: vec![0] },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("bytes"),
|
||||
Token::String("\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::Bytes { bytes: vec![0] },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("bytes"),
|
||||
Token::Bytes(b"\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::Bytes { bytes: vec![0] },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("bytes"),
|
||||
Token::ByteBuf(b"\0"),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
|
||||
assert_de_tokens(
|
||||
&Untagged::Bytes { bytes: vec![0] },
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "Untagged",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("bytes"),
|
||||
Token::Seq { len: Some(1) },
|
||||
Token::U8(0),
|
||||
Token::SeqEnd,
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains_flatten() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(untagged)]
|
||||
enum Data {
|
||||
A {
|
||||
a: i32,
|
||||
#[serde(flatten)]
|
||||
flat: Flat,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct Flat {
|
||||
b: i32,
|
||||
}
|
||||
|
||||
let data = Data::A {
|
||||
a: 0,
|
||||
flat: Flat { b: 0 },
|
||||
};
|
||||
|
||||
assert_tokens(
|
||||
&data,
|
||||
&[
|
||||
Token::Map { len: None },
|
||||
Token::Str("a"),
|
||||
Token::I32(0),
|
||||
Token::Str("b"),
|
||||
Token::I32(0),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains_flatten_with_integer_key() {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Untagged {
|
||||
Variant {
|
||||
#[serde(flatten)]
|
||||
map: BTreeMap<u64, String>,
|
||||
},
|
||||
}
|
||||
|
||||
assert_tokens(
|
||||
&Untagged::Variant {
|
||||
map: {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(100, "BTreeMap".to_owned());
|
||||
map
|
||||
},
|
||||
},
|
||||
&[
|
||||
Token::Map { len: None },
|
||||
Token::U64(100),
|
||||
Token::Str("BTreeMap"),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expecting_message() {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[serde(expecting = "something strange...")]
|
||||
enum Enum {
|
||||
Untagged,
|
||||
}
|
||||
|
||||
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], "something strange...");
|
||||
}
|
||||
+105
-58
@@ -4,6 +4,7 @@
|
||||
|
||||
#![deny(warnings)]
|
||||
#![allow(
|
||||
confusable_idents,
|
||||
unknown_lints,
|
||||
mixed_script_confusables,
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
@@ -17,8 +18,12 @@
|
||||
clippy::ptr_arg,
|
||||
clippy::too_many_lines,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::type_repetition_in_bounds
|
||||
clippy::type_repetition_in_bounds,
|
||||
// We use lots of declarations inside function bodies to avoid conflicts,
|
||||
// but they aren't used. We just want to make sure they compile.
|
||||
dead_code,
|
||||
)]
|
||||
#![deny(clippy::collection_is_never_read)]
|
||||
|
||||
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
@@ -287,60 +292,60 @@ fn test_gen() {
|
||||
assert::<EmptyEnumVariant>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct NonAsciiIdents {
|
||||
pub struct NonAsciiIdents {
|
||||
σ: f64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct EmptyBraced {}
|
||||
pub struct EmptyBraced {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct EmptyBracedDenyUnknown {}
|
||||
pub struct EmptyBracedDenyUnknown {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct BracedSkipAll {
|
||||
pub struct BracedSkipAll {
|
||||
#[serde(skip_deserializing)]
|
||||
f: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct BracedSkipAllDenyUnknown {
|
||||
pub struct BracedSkipAllDenyUnknown {
|
||||
#[serde(skip_deserializing)]
|
||||
f: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct EmptyTuple();
|
||||
pub struct EmptyTuple();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct EmptyTupleDenyUnknown();
|
||||
pub struct EmptyTupleDenyUnknown();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TupleSkipAll(#[serde(skip_deserializing)] u8);
|
||||
pub struct TupleSkipAll(#[serde(skip_deserializing)] u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
|
||||
pub struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EmptyEnum {}
|
||||
pub enum EmptyEnum {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
enum EmptyEnumDenyUnknown {}
|
||||
pub enum EmptyEnumDenyUnknown {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EnumSkipAll {
|
||||
pub enum EnumSkipAll {
|
||||
#[serde(skip_deserializing)]
|
||||
#[allow(dead_code)]
|
||||
Variant,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum EmptyVariants {
|
||||
pub enum EmptyVariants {
|
||||
Braced {},
|
||||
Tuple(),
|
||||
BracedSkip {
|
||||
@@ -352,7 +357,7 @@ fn test_gen() {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
enum EmptyVariantsDenyUnknown {
|
||||
pub enum EmptyVariantsDenyUnknown {
|
||||
Braced {},
|
||||
Tuple(),
|
||||
BracedSkip {
|
||||
@@ -364,21 +369,21 @@ fn test_gen() {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct UnitDenyUnknown;
|
||||
pub struct UnitDenyUnknown;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct EmptyArray {
|
||||
pub struct EmptyArray {
|
||||
empty: [X; 0],
|
||||
}
|
||||
|
||||
enum Or<A, B> {
|
||||
pub enum Or<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged, remote = "Or")]
|
||||
enum OrDef<A, B> {
|
||||
pub enum OrDef<A, B> {
|
||||
A(A),
|
||||
B(B),
|
||||
}
|
||||
@@ -390,7 +395,7 @@ fn test_gen() {
|
||||
struct StrDef<'a>(&'a str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Remote<'a> {
|
||||
pub struct Remote<'a> {
|
||||
#[serde(with = "OrDef")]
|
||||
or: Or<u8, bool>,
|
||||
#[serde(borrow, with = "StrDef")]
|
||||
@@ -398,7 +403,7 @@ fn test_gen() {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum BorrowVariant<'a> {
|
||||
pub enum BorrowVariant<'a> {
|
||||
#[serde(borrow, with = "StrDef")]
|
||||
S(Str<'a>),
|
||||
}
|
||||
@@ -415,14 +420,14 @@ fn test_gen() {
|
||||
|
||||
// This would not work if SDef::serialize / deserialize are private.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RemoteVisibility {
|
||||
pub struct RemoteVisibility {
|
||||
#[serde(with = "vis::SDef")]
|
||||
s: vis::S,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "Self")]
|
||||
struct RemoteSelf;
|
||||
pub struct RemoteSelf;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum ExternallyTaggedVariantWith {
|
||||
@@ -546,26 +551,45 @@ fn test_gen() {
|
||||
assert::<FlattenWith>();
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct FlattenDenyUnknown<T> {
|
||||
pub struct Flatten<T> {
|
||||
#[serde(flatten)]
|
||||
t: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrStruct<'a> {
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct FlattenDenyUnknown<T> {
|
||||
#[serde(flatten)]
|
||||
t: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SkipDeserializing<T> {
|
||||
#[serde(skip_deserializing)]
|
||||
flat: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SkipDeserializingDenyUnknown<T> {
|
||||
#[serde(skip_deserializing)]
|
||||
flat: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct StaticStrStruct<'a> {
|
||||
a: &'a str,
|
||||
b: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
|
||||
pub struct StaticStrTupleStruct<'a>(&'a str, &'static str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct StaticStrNewtypeStruct(&'static str);
|
||||
pub struct StaticStrNewtypeStruct(&'static str);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum StaticStrEnum<'a> {
|
||||
pub enum StaticStrEnum<'a> {
|
||||
Struct { a: &'a str, b: &'static str },
|
||||
Tuple(&'a str, &'static str),
|
||||
Newtype(&'static str),
|
||||
@@ -639,6 +663,7 @@ fn test_gen() {
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct Restricted {
|
||||
pub(super) a: usize,
|
||||
pub(in super::inner) b: usize,
|
||||
@@ -648,7 +673,7 @@ fn test_gen() {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(tag = "t", content = "c")]
|
||||
enum AdjacentlyTaggedVoid {}
|
||||
pub enum AdjacentlyTaggedVoid {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum SkippedVariant<T> {
|
||||
@@ -661,14 +686,14 @@ fn test_gen() {
|
||||
assert::<SkippedVariant<X>>();
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ImplicitlyBorrowedOption<'a> {
|
||||
#[allow(dead_code)]
|
||||
pub struct ImplicitlyBorrowedOption<'a> {
|
||||
option: std::option::Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum UntaggedNewtypeVariantWith {
|
||||
#[allow(dead_code)]
|
||||
pub enum UntaggedNewtypeVariantWith {
|
||||
Newtype(
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
@@ -678,7 +703,8 @@ fn test_gen() {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct TransparentWith {
|
||||
#[allow(dead_code)]
|
||||
pub struct TransparentWith {
|
||||
#[serde(serialize_with = "ser_x")]
|
||||
#[serde(deserialize_with = "de_x")]
|
||||
x: X,
|
||||
@@ -686,41 +712,61 @@ fn test_gen() {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum UntaggedWithBorrow<'a> {
|
||||
Single(#[serde(borrow)] RelObject<'a>),
|
||||
Many(#[serde(borrow)] Vec<RelObject<'a>>),
|
||||
#[allow(dead_code)]
|
||||
pub enum UntaggedWithBorrow<'a> {
|
||||
Single(
|
||||
#[serde(borrow)]
|
||||
#[allow(dead_code)]
|
||||
RelObject<'a>,
|
||||
),
|
||||
Many(
|
||||
#[serde(borrow)]
|
||||
#[allow(dead_code)]
|
||||
Vec<RelObject<'a>>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RelObject<'a> {
|
||||
#[allow(dead_code)]
|
||||
pub struct RelObject<'a> {
|
||||
ty: &'a str,
|
||||
#[allow(dead_code)]
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FlattenSkipSerializing<T> {
|
||||
pub struct FlattenSkipSerializing<T> {
|
||||
#[serde(flatten, skip_serializing)]
|
||||
#[allow(dead_code)]
|
||||
flat: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FlattenSkipSerializingIf<T> {
|
||||
pub struct FlattenSkipSerializingIf<T> {
|
||||
#[serde(flatten, skip_serializing_if = "StdOption::is_none")]
|
||||
flat: StdOption<T>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FlattenSkipDeserializing<T> {
|
||||
pub struct FlattenSkipDeserializing<T> {
|
||||
#[serde(flatten, skip_deserializing)]
|
||||
flat: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Inner<T> {
|
||||
Builder {
|
||||
s: T,
|
||||
#[serde(flatten)]
|
||||
o: T,
|
||||
},
|
||||
Default {
|
||||
s: T,
|
||||
},
|
||||
}
|
||||
|
||||
// https://github.com/serde-rs/serde/issues/1804
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum Message {
|
||||
pub enum Message {
|
||||
#[serde(skip)]
|
||||
#[allow(dead_code)]
|
||||
String(String),
|
||||
@@ -729,7 +775,8 @@ fn test_gen() {
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[repr(packed)]
|
||||
#[repr(C, packed)]
|
||||
#[allow(dead_code)]
|
||||
struct Packed {
|
||||
x: u8,
|
||||
y: u16,
|
||||
@@ -738,8 +785,7 @@ fn test_gen() {
|
||||
macro_rules! deriving {
|
||||
($field:ty) => {
|
||||
#[derive(Deserialize)]
|
||||
struct MacroRules<'a> {
|
||||
#[allow(dead_code)]
|
||||
pub struct MacroRules<'a> {
|
||||
field: $field,
|
||||
}
|
||||
};
|
||||
@@ -754,21 +800,22 @@ fn test_gen() {
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct BorrowLifetimeInsideMacro<'a> {
|
||||
pub struct BorrowLifetimeInsideMacro<'a> {
|
||||
#[serde(borrow = "'a")]
|
||||
#[allow(dead_code)]
|
||||
f: mac!(Cow<'a, str>),
|
||||
pub f: mac!(Cow<'a, str>),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Struct {
|
||||
pub struct Struct {
|
||||
#[serde(serialize_with = "vec_first_element")]
|
||||
vec: Vec<Self>,
|
||||
pub vec: Vec<Self>,
|
||||
}
|
||||
|
||||
assert_ser::<Struct>();
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
|
||||
struct GenericUnitStruct<const N: usize>;
|
||||
pub struct GenericUnitStruct<const N: usize>;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -855,7 +902,7 @@ where
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(tag = "tag")]
|
||||
enum InternallyTagged {
|
||||
pub enum InternallyTagged {
|
||||
#[serde(deserialize_with = "deserialize_generic")]
|
||||
Unit,
|
||||
|
||||
@@ -876,14 +923,14 @@ where
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[repr(packed)]
|
||||
#[repr(C, packed)]
|
||||
pub struct RemotePacked {
|
||||
pub a: u16,
|
||||
pub b: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[repr(packed)]
|
||||
#[repr(C, packed)]
|
||||
#[serde(remote = "RemotePacked")]
|
||||
pub struct RemotePackedDef {
|
||||
a: u16,
|
||||
@@ -894,14 +941,14 @@ impl Drop for RemotePackedDef {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[repr(C, packed)]
|
||||
pub struct RemotePackedNonCopy {
|
||||
pub a: u16,
|
||||
pub b: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[repr(packed)]
|
||||
#[repr(C, packed)]
|
||||
#[serde(remote = "RemotePackedNonCopy")]
|
||||
pub struct RemotePackedNonCopyDef {
|
||||
a: u16,
|
||||
|
||||
+5
-1288
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
#![allow(clippy::redundant_field_names)]
|
||||
#![allow(clippy::redundant_field_names, dead_code)]
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
@@ -7,14 +7,17 @@ mod remote {
|
||||
|
||||
pub struct PrimitivePriv(u8);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct PrimitivePub(pub u8);
|
||||
|
||||
pub struct NewtypePriv(Unit);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct NewtypePub(pub Unit);
|
||||
|
||||
pub struct TuplePriv(u8, Unit);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct TuplePub(pub u8, pub Unit);
|
||||
|
||||
pub struct StructPriv {
|
||||
@@ -22,6 +25,7 @@ mod remote {
|
||||
b: Unit,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct StructPub {
|
||||
pub a: u8,
|
||||
pub b: Unit,
|
||||
@@ -86,12 +90,14 @@ mod remote {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum EnumGeneric<T> {
|
||||
Variant(T),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct Test {
|
||||
#[serde(with = "UnitDef")]
|
||||
unit: remote::Unit,
|
||||
@@ -132,6 +138,7 @@ struct Test {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::Unit")]
|
||||
#[allow(dead_code)]
|
||||
struct UnitDef;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -140,6 +147,7 @@ struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::PrimitivePub")]
|
||||
#[allow(dead_code)]
|
||||
struct PrimitivePubDef(u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -148,6 +156,7 @@ struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitD
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::NewtypePub")]
|
||||
#[allow(dead_code)]
|
||||
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -159,6 +168,7 @@ struct TuplePrivDef(
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::TuplePub")]
|
||||
#[allow(dead_code)]
|
||||
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -174,6 +184,7 @@ struct StructPrivDef {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::StructPub")]
|
||||
#[allow(dead_code)]
|
||||
struct StructPubDef {
|
||||
a: u8,
|
||||
|
||||
@@ -190,17 +201,20 @@ struct StructGenericWithGetterDef<T> {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::StructGeneric<u8>")]
|
||||
#[allow(dead_code)]
|
||||
struct StructConcrete {
|
||||
value: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "remote::EnumGeneric<u8>")]
|
||||
#[allow(dead_code)]
|
||||
enum EnumConcrete {
|
||||
Variant(u8),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum ErrorKind {
|
||||
NotFound,
|
||||
PermissionDenied,
|
||||
@@ -211,6 +225,7 @@ enum ErrorKind {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "ErrorKind")]
|
||||
#[non_exhaustive]
|
||||
#[allow(dead_code)]
|
||||
enum ErrorKindDef {
|
||||
NotFound,
|
||||
PermissionDenied,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![allow(clippy::used_underscore_binding)]
|
||||
#![allow(clippy::used_underscore_binding, dead_code)]
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
@@ -41,7 +41,7 @@ fn test_self() {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Tuple(
|
||||
pub struct Tuple(
|
||||
Box<Self>,
|
||||
Box<<Self as Trait>::Assoc>,
|
||||
[(); Self::ASSOC],
|
||||
@@ -60,7 +60,7 @@ fn test_self() {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
enum Enum {
|
||||
pub enum Enum {
|
||||
Struct {
|
||||
_f1: Box<Self>,
|
||||
_f2: Box<<Self as Trait>::Assoc>,
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#![allow(clippy::derive_partial_eq_without_eq, clippy::unreadable_literal)]
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
|
||||
use fnv::FnvHasher;
|
||||
use serde_derive::Serialize;
|
||||
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::num::Wrapping;
|
||||
use std::num::{Saturating, Wrapping};
|
||||
use std::ops::Bound;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::{Rc, Weak as RcWeak};
|
||||
@@ -220,7 +219,7 @@ fn test_hashset() {
|
||||
&[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd],
|
||||
);
|
||||
assert_ser_tokens(
|
||||
&hashset![FnvHasher @ 1],
|
||||
&hashset![foldhash::fast::FixedState; 1],
|
||||
&[Token::Seq { len: Some(1) }, Token::I32(1), Token::SeqEnd],
|
||||
);
|
||||
}
|
||||
@@ -300,7 +299,7 @@ fn test_hashmap() {
|
||||
],
|
||||
);
|
||||
assert_ser_tokens(
|
||||
&hashmap![FnvHasher @ 1 => 2],
|
||||
&hashmap![foldhash::fast::FixedState; 1 => 2],
|
||||
&[
|
||||
Token::Map { len: Some(1) },
|
||||
Token::I32(1),
|
||||
@@ -500,6 +499,38 @@ fn test_range_inclusive() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_from() {
|
||||
assert_ser_tokens(
|
||||
&(1u32..),
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "RangeFrom",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("start"),
|
||||
Token::U32(1),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_to() {
|
||||
assert_ser_tokens(
|
||||
&(..2u32),
|
||||
&[
|
||||
Token::Struct {
|
||||
name: "RangeTo",
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("end"),
|
||||
Token::U32(2),
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound() {
|
||||
assert_ser_tokens(
|
||||
@@ -592,6 +623,11 @@ fn test_wrapping() {
|
||||
assert_ser_tokens(&Wrapping(1usize), &[Token::U64(1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_saturating() {
|
||||
assert_ser_tokens(&Saturating(1usize), &[Token::U64(1)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rc_dst() {
|
||||
assert_ser_tokens(&Rc::<str>::from("s"), &[Token::Str("s")]);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#![allow(
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::extra_unused_type_parameters,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::type_repetition_in_bounds
|
||||
)]
|
||||
|
||||
@@ -27,19 +29,21 @@ mod fake_serde {
|
||||
{
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait Serialize {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait Deserialize<'a>: Sized {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error>;
|
||||
}
|
||||
}
|
||||
|
||||
trait AssertNotSerdeSerialize {}
|
||||
pub trait AssertNotSerdeSerialize {}
|
||||
|
||||
impl<T: serde::Serialize> AssertNotSerdeSerialize for T {}
|
||||
|
||||
trait AssertNotSerdeDeserialize<'a> {}
|
||||
pub trait AssertNotSerdeDeserialize<'a> {}
|
||||
|
||||
impl<'a, T: serde::Deserialize<'a>> AssertNotSerdeDeserialize<'a> for T {}
|
||||
|
||||
@@ -63,7 +63,7 @@ fn test_map_access_to_enum() {
|
||||
type Value = Potential;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "a map")
|
||||
formatter.write_str("a map")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum E {
|
||||
S1 {
|
||||
#[serde(alias = "a", alias = "b", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "c" and "b"
|
||||
#[serde(alias = "c")]
|
||||
b: (),
|
||||
|
||||
#[serde(skip_deserializing)]
|
||||
c: (),
|
||||
},
|
||||
|
||||
S2 {
|
||||
#[serde(alias = "b", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "c"
|
||||
#[serde(rename = "c")]
|
||||
b: (),
|
||||
},
|
||||
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
S3 {
|
||||
#[serde(alias = "B", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "b" because this collides with the "B" above after
|
||||
// applying rename rules
|
||||
b: (),
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum E1 {
|
||||
#[serde(alias = "a", alias = "b", alias = "c")]
|
||||
a,
|
||||
|
||||
// Warning on "c" and "b"
|
||||
#[serde(alias = "c")]
|
||||
b,
|
||||
|
||||
#[serde(skip_deserializing)]
|
||||
c,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum E2 {
|
||||
#[serde(alias = "b", alias = "c")]
|
||||
a,
|
||||
|
||||
// Warning on "c"
|
||||
#[serde(rename = "c")]
|
||||
b,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
enum E3 {
|
||||
#[serde(alias = "B", alias = "c")]
|
||||
a,
|
||||
|
||||
// Warning on "b" because this collides with the "B" above after applying
|
||||
// rename rules
|
||||
b,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
__FAIL__;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
error[E0425]: cannot find value `__FAIL__` in this scope
|
||||
--> tests/ui/conflict/alias-enum.rs:74:5
|
||||
|
|
||||
74 | __FAIL__;
|
||||
| ^^^^^^^^ not found in this scope
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:13:9
|
||||
|
|
||||
8 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
13 | b: (),
|
||||
| ^ no value can reach this
|
||||
|
|
||||
= note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:12:25
|
||||
|
|
||||
8 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
12 | #[serde(alias = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:24:26
|
||||
|
|
||||
20 | #[serde(alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
24 | #[serde(rename = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:35:9
|
||||
|
|
||||
30 | #[serde(alias = "B", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
35 | b: (),
|
||||
| ^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:46:5
|
||||
|
|
||||
41 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
46 | b,
|
||||
| ^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:45:21
|
||||
|
|
||||
41 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
45 | #[serde(alias = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:58:22
|
||||
|
|
||||
54 | #[serde(alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
58 | #[serde(rename = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias-enum.rs:70:5
|
||||
|
|
||||
65 | #[serde(alias = "B", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
70 | b,
|
||||
| ^ no value can reach this
|
||||
@@ -0,0 +1,39 @@
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct S1 {
|
||||
#[serde(alias = "a", alias = "b", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "c" and "b"
|
||||
#[serde(alias = "c")]
|
||||
b: (),
|
||||
|
||||
#[serde(skip_deserializing)]
|
||||
c: (),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct S2 {
|
||||
#[serde(alias = "b", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "c"
|
||||
#[serde(rename = "c")]
|
||||
b: (),
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
struct S3 {
|
||||
#[serde(alias = "B", alias = "c")]
|
||||
a: (),
|
||||
|
||||
// Warning on "b" because this collides with the "B" above after applying
|
||||
// rename rules
|
||||
b: (),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
__FAIL__;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
error[E0425]: cannot find value `__FAIL__` in this scope
|
||||
--> tests/ui/conflict/alias.rs:38:5
|
||||
|
|
||||
38 | __FAIL__;
|
||||
| ^^^^^^^^ not found in this scope
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias.rs:10:5
|
||||
|
|
||||
5 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
10 | b: (),
|
||||
| ^ no value can reach this
|
||||
|
|
||||
= note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias.rs:9:21
|
||||
|
|
||||
5 | #[serde(alias = "a", alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
9 | #[serde(alias = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias.rs:22:22
|
||||
|
|
||||
18 | #[serde(alias = "b", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
22 | #[serde(rename = "c")]
|
||||
| ^^^ no value can reach this
|
||||
|
||||
warning: unreachable pattern
|
||||
--> tests/ui/conflict/alias.rs:34:5
|
||||
|
|
||||
29 | #[serde(alias = "B", alias = "c")]
|
||||
| --- matches all the relevant values
|
||||
...
|
||||
34 | b: (),
|
||||
| ^ no value can reach this
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user