mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-27 15:47:57 +00:00
Compare commits
733 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a866b336f1 | |||
| 5adc9e816c | |||
| ab581789f4 | |||
| 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 | |||
| 5d036515ed | |||
| a741293886 | |||
| f8d0b26d2f | |||
| 7007c1bea5 | |||
| 0d8ebac7e1 | |||
| 212c42c74f | |||
| 919f6be887 | |||
| c0f70428ba | |||
| e797c90ebd | |||
| fc04d1219a | |||
| df4ad5884d | |||
| 3c7dd6fc1e | |||
| 8b196ea1c8 | |||
| 1f8c8ad5a3 | |||
| 870925d503 | |||
| d593215ef7 | |||
| 110af31b48 | |||
| 360606b9a6 | |||
| 151b45ae36 | |||
| 2ea7e1300f | |||
| 4617c957b9 | |||
| 2547ed83ca | |||
| bfcd44704f | |||
| 7b548db91e | |||
| d39dea85ad | |||
| 5e56c9fba8 | |||
| 8d3a03288b | |||
| cb490ec16d | |||
| 45271c3676 | |||
| 6a097eca93 | |||
| 84d1c5385d | |||
| 05a5b7e3c6 | |||
| 3bff326fb3 | |||
| aaadd93878 | |||
| 9c864f0b02 | |||
| 070cce0d9c | |||
| b58e8bac12 | |||
| ada50b077e | |||
| 5e313a7330 | |||
| 2a36d11238 | |||
| b6685cf9dd | |||
| fc273c6763 | |||
| bd7b0e257e | |||
| 73931692b2 | |||
| 4d93e9f44c | |||
| da55ed7e8d | |||
| e3617e1f28 | |||
| 431636af0d | |||
| 891ced598a | |||
| 57dc0ee769 | |||
| 5e102c4da1 | |||
| 5c33931422 | |||
| 4aa54222f4 | |||
| ef4f860384 | |||
| 9bd52ec5c1 | |||
| 5cdd82d41e | |||
| 110bf10481 | |||
| 43035f6f37 | |||
| 83b1a3d5dc | |||
| 878110a4bc | |||
| 59ec8b7db2 | |||
| cae1b43829 | |||
| 99fde4ee3e | |||
| afe3872810 | |||
| 3a3e6bf103 | |||
| 935f0bd70f | |||
| 5c18bfeda6 | |||
| 957ef206d1 | |||
| 0c367838cc | |||
| 2023cf345f | |||
| 033d05f70b | |||
| fe4e3fd3b0 | |||
| 8a8a8a70ee | |||
| 339dca828d | |||
| 0d7349fa4e | |||
| 830528d5b1 | |||
| ab90fbc7c9 | |||
| 3eec111e8f | |||
| 9388433642 | |||
| ba12070665 | |||
| a57a324d72 | |||
| 92e91b3557 | |||
| 4dcf791706 | |||
| e77900fb94 | |||
| 1b14cadf20 | |||
| 4f59cd217a | |||
| 27c8b2d66a | |||
| 89976c2712 | |||
| c91737fef1 | |||
| a100719bc6 | |||
| 9a0e149225 | |||
| 9350927903 | |||
| 677c13a4ec | |||
| ee8e1ee7ff | |||
| f969080b9f | |||
| c2b16bfbb0 | |||
| e7df53701c | |||
| 02c34e490b | |||
| 427c839b3d | |||
| 48aa054f53 | |||
| 3616860203 | |||
| 861b0dfea2 | |||
| 8b3d71ae2d | |||
| ff5442cd9e | |||
| 92d686f9a5 | |||
| 7b09cccd77 | |||
| 6f1f38d046 | |||
| db8f06467b | |||
| 91ec1c290f | |||
| 0676673ca5 | |||
| 7a4335d664 | |||
| 31a0e73489 | |||
| 74fe70855f | |||
| e74925bc43 | |||
| 56be1c203e | |||
| 2f9bf4d3eb | |||
| ad94aed753 | |||
| 30db83fc44 | |||
| b0f7b00e1f | |||
| 7255e192d8 | |||
| 2102e1aa42 | |||
| 85d5c1fd38 | |||
| b789286bc3 | |||
| a6a8a334f7 | |||
| 78a11a27b6 | |||
| d2d7bad04a | |||
| b978854258 | |||
| 0fb672a1ef | |||
| dd9913675d | |||
| 11677ad926 | |||
| 25a53f10db | |||
| 26e2ef001c | |||
| 30f79b3b2e | |||
| 89f84c2915 | |||
| 6882285be0 | |||
| 3260bc5896 | |||
| 6140b6f527 | |||
| 4cabc9f293 | |||
| aa7c6345a4 | |||
| f709fc05b0 | |||
| 089aae1292 | |||
| 855acaf112 | |||
| 7ca7720262 | |||
| 78fea3aa4a | |||
| 1efb8b6a53 | |||
| bc1960b106 | |||
| 967023b755 | |||
| bb51e68f16 | |||
| 27414c90a8 | |||
| 50e2f4b213 | |||
| 22be673beb | |||
| 166c89fabf | |||
| 6e0b13eedb | |||
| 7e8f978ca9 | |||
| 6c0e838a7c | |||
| d3da41927a | |||
| 425a4b7a74 | |||
| 63c65ef742 | |||
| e838b0bd81 | |||
| 041e99c78a | |||
| 07dcc4f7fe | |||
| b88052d875 | |||
| a28292764c | |||
| 2027088741 | |||
| e2d8589976 | |||
| c8a9f99d14 | |||
| 645d04012d | |||
| 100ddada2f | |||
| 2ef1cd4b35 | |||
| be9c3fd69d | |||
| ef522e1d16 | |||
| 1ddb6c2fdb | |||
| eb3f2329af | |||
| 9e8f14816b | |||
| 4e5e55bf1c | |||
| 4513a9e6a7 | |||
| 4f922e4e5b | |||
| 993966600e | |||
| 5b96cf1bde | |||
| f3d50e5209 | |||
| ab21d4d017 | |||
| f7c5d93e6a | |||
| 52a7d40e6e | |||
| 348bc6b257 | |||
| 03da66c805 | |||
| f75426f47e | |||
| 662fc3861c | |||
| 28c10020b9 | |||
| 89c8d85de9 | |||
| 6502838f27 | |||
| c93a0f335a | |||
| 8264e002a7 | |||
| 117ef22142 | |||
| 3fb5e71c33 | |||
| 296db177e2 | |||
| e4a4389177 | |||
| 7aa0453c3b | |||
| 09b78b24e9 | |||
| a622b8a74a | |||
| 399ef081ec | |||
| 3686277e14 | |||
| 807bd20a64 | |||
| ed9a140348 | |||
| 2de7c2bea2 | |||
| e6a4a3772e | |||
| 0fca04e1a6 | |||
| 92bfc8d3af | |||
| fa0312ac45 | |||
| 1920b694aa | |||
| 3bfd41d624 | |||
| 290449f19b | |||
| 3a1f387e69 | |||
| 541603ac94 | |||
| 0666fbfa20 | |||
| ea071ae1d4 | |||
| 992a01bad2 | |||
| d640b5624f | |||
| 48479e4bae | |||
| dfaf48bc09 | |||
| 4cf1fec575 | |||
| ee7d77defa | |||
| d0dfc4577e | |||
| bbbd1d24c9 | |||
| fb3a9e0d7c | |||
| 5ffebeb6ef | |||
| 75db73066b | |||
| 2796833c82 | |||
| 95730dc7f7 | |||
| 795261919f | |||
| 3783a30ae7 | |||
| b61ec84886 | |||
| 780a461d92 | |||
| c604bdbfe4 | |||
| 9fef892f6d | |||
| b1c7db47b8 | |||
| e76e87a430 | |||
| 51799dd654 | |||
| 732ac49321 | |||
| 983347484e |
@@ -0,0 +1 @@
|
|||||||
|
github: dtolnay
|
||||||
+54
-42
@@ -18,16 +18,22 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@nightly
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
- run: cd test_suite && cargo test --features unstable
|
- 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:
|
windows:
|
||||||
name: Test suite (windows)
|
name: Test suite (windows)
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@nightly
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
|
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
|
||||||
|
|
||||||
@@ -40,17 +46,16 @@ jobs:
|
|||||||
rust: [stable, beta]
|
rust: [stable, beta]
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@master
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: ${{matrix.rust}}
|
toolchain: ${{matrix.rust}}
|
||||||
- run: cd serde && cargo build --features rc
|
- run: cd serde && cargo build --features rc
|
||||||
- run: cd serde && cargo build --no-default-features
|
- run: cd serde && cargo build --no-default-features
|
||||||
- run: cd serde_test && cargo build
|
- run: cd test_suite/no_std && cargo build
|
||||||
- run: cd serde_test && cargo test --features serde/derive,serde/rc
|
|
||||||
|
|
||||||
nightly:
|
nightly:
|
||||||
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
|
name: Rust nightly${{matrix.os == 'windows' && ' (windows)' || ''}}
|
||||||
runs-on: ${{matrix.os}}-latest
|
runs-on: ${{matrix.os}}-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -58,13 +63,14 @@ jobs:
|
|||||||
os: [ubuntu, windows]
|
os: [ubuntu, windows]
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@nightly
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
- run: cd serde && cargo build
|
- run: cd serde && cargo build
|
||||||
- run: cd serde && cargo build --no-default-features
|
- 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 alloc
|
||||||
- run: cd serde && cargo build --no-default-features --features rc,alloc
|
- run: cd serde && cargo build --no-default-features --features rc,alloc
|
||||||
- run: cd serde && cargo test --features derive,rc,unstable
|
- run: cd serde && cargo build --no-default-features --features unstable
|
||||||
|
- run: cd serde_core && cargo test --features rc,unstable
|
||||||
- run: cd test_suite/no_std && cargo build
|
- run: cd test_suite/no_std && cargo build
|
||||||
if: matrix.os != 'windows'
|
if: matrix.os != 'windows'
|
||||||
- run: cd serde_derive && cargo check --tests
|
- run: cd serde_derive && cargo check --tests
|
||||||
@@ -78,55 +84,58 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
rust: [1.19.0, 1.20.0, 1.21.0, 1.25.0, 1.26.0, 1.34.0]
|
rust: [1.56.0, 1.60.0]
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@master
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: ${{matrix.rust}}
|
toolchain: ${{matrix.rust}}
|
||||||
|
- run: sed -i '/"test_suite"/d' Cargo.toml
|
||||||
- run: cd serde && cargo build --features rc
|
- run: cd serde && cargo build --features rc
|
||||||
- run: cd serde && cargo build --no-default-features
|
- run: cd serde && cargo build --no-default-features
|
||||||
- run: cd serde && cargo build
|
- run: cd serde && cargo build --no-default-features --features alloc
|
||||||
- run: cd serde_test && cargo build
|
|
||||||
|
|
||||||
more:
|
|
||||||
name: Rust ${{matrix.rust}}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
rust: [1.27.0, 1.28.0]
|
|
||||||
timeout-minutes: 45
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: ${{matrix.rust}}
|
|
||||||
# Work around failing to parse manifest because editions are unstable.
|
|
||||||
- run: sed -i /test_suite/d Cargo.toml
|
|
||||||
- run: cd serde && cargo build --no-default-features
|
|
||||||
- run: cd serde && cargo build
|
- run: cd serde && cargo build
|
||||||
|
|
||||||
derive:
|
derive:
|
||||||
name: Rust 1.56.0
|
name: Rust 1.61.0
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@1.56.0
|
- 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 --no-default-features
|
||||||
- run: cd serde && cargo check
|
- run: cd serde && cargo check
|
||||||
- run: cd serde_derive && cargo check
|
- run: cd serde_derive && cargo check
|
||||||
|
|
||||||
alloc:
|
minimal:
|
||||||
name: Rust 1.36.0
|
name: Minimal versions
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@1.36.0
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
- run: cd serde && cargo build --no-default-features --features alloc
|
- 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:
|
clippy:
|
||||||
name: Clippy
|
name: Clippy
|
||||||
@@ -134,12 +143,12 @@ jobs:
|
|||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@clippy
|
- uses: dtolnay/rust-toolchain@clippy
|
||||||
- run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
|
- 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 && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
- run: cd serde_test && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
|
||||||
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
|
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
|
||||||
- run: cd test_suite/no_std && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
- run: cd test_suite/no_std && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
|
||||||
@@ -148,10 +157,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@miri
|
- uses: dtolnay/rust-toolchain@miri
|
||||||
|
with:
|
||||||
|
toolchain: nightly-2025-05-16 # https://github.com/rust-lang/miri/issues/4323
|
||||||
- run: cargo miri setup
|
- 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:
|
env:
|
||||||
MIRIFLAGS: -Zmiri-strict-provenance
|
MIRIFLAGS: -Zmiri-strict-provenance
|
||||||
- run: cd test_suite && cargo miri test --features unstable
|
- run: cd test_suite && cargo miri test --features unstable
|
||||||
@@ -164,6 +175,7 @@ jobs:
|
|||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
- uses: dtolnay/install@cargo-outdated
|
- uses: dtolnay/install@cargo-outdated
|
||||||
- run: cargo outdated --workspace --exit-code 1
|
- run: cargo outdated --workspace --exit-code 1
|
||||||
|
|||||||
+2
-4
@@ -1,4 +1,2 @@
|
|||||||
target/
|
/target/
|
||||||
**/*.rs.bk
|
/Cargo.lock
|
||||||
*.sw[po]
|
|
||||||
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
|
easier to iterate and fix it locally than waiting for the CI servers to run
|
||||||
tests for you.
|
tests for you.
|
||||||
|
|
||||||
##### In the [`serde`] directory
|
##### In the [`serde_core`] directory
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Test all the example code in Serde documentation
|
# Test all the example code in Serde documentation
|
||||||
cargo test --features derive
|
cargo test
|
||||||
```
|
```
|
||||||
|
|
||||||
##### In the [`test_suite`] directory
|
##### 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.
|
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
|
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
|
||||||
|
|
||||||
## Conduct
|
## Conduct
|
||||||
|
|||||||
+12
-1
@@ -1,8 +1,19 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_derive_internals",
|
"serde_derive_internals",
|
||||||
"serde_test",
|
|
||||||
"test_suite",
|
"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.19+]][Rust 1.19] [![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
|
[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
|
[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster
|
||||||
[Latest Version]: https://img.shields.io/crates/v/serde.svg
|
[Latest Version]: https://img.shields.io/crates/v/serde.svg
|
||||||
[crates.io]: https://crates.io/crates/serde
|
[crates.io]: https://crates.io/crates/serde
|
||||||
[serde: rustc 1.19+]: https://img.shields.io/badge/serde-rustc_1.19+-lightgray.svg
|
[serde msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray
|
||||||
[serde_derive: rustc 1.56+]: https://img.shields.io/badge/serde_derive-rustc_1.56+-lightgray.svg
|
[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray
|
||||||
[Rust 1.19]: https://blog.rust-lang.org/2017/07/20/Rust-1.19.html
|
|
||||||
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html
|
[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.**
|
**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:
|
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)
|
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||||
- [Examples](https://serde.rs/examples.html)
|
- [Examples](https://serde.rs/examples.html)
|
||||||
@@ -27,7 +27,7 @@ You may be looking for:
|
|||||||
<details>
|
<details>
|
||||||
<summary>
|
<summary>
|
||||||
Click to show Cargo.toml.
|
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>
|
</summary>
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
@@ -48,7 +48,7 @@ serde_json = "1.0"
|
|||||||
<p></p>
|
<p></p>
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
|
|||||||
+4
-4
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
You may be looking for:
|
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)
|
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||||
- [Examples](https://serde.rs/examples.html)
|
- [Examples](https://serde.rs/examples.html)
|
||||||
@@ -16,7 +16,7 @@ You may be looking for:
|
|||||||
## Serde in action
|
## Serde in action
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
@@ -46,8 +46,8 @@ fn main() {
|
|||||||
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
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
|
congregate will be able to help you out. For chat, consider trying the
|
||||||
[#rust-questions] or [#rust-beginners] channels of the unofficial community
|
[#rust-questions] or [#rust-beginners] channels of the unofficial community
|
||||||
Discord (invite: <https://discord.gg/rust-lang-community>, the [#rust-usage] or
|
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage]
|
||||||
[#beginners] channels of the official Rust Project Discord (invite:
|
or [#beginners] channels of the official Rust Project Discord (invite:
|
||||||
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
|
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
|
||||||
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
|
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
|
||||||
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
|
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
|
||||||
|
|||||||
+18
-16
@@ -1,34 +1,36 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.165" # remember to update html_root_url and serde_derive dependency
|
version = "1.0.228"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
categories = ["encoding", "no-std"]
|
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||||
description = "A generic serialization/deserialization framework"
|
description = "A generic serialization/deserialization framework"
|
||||||
documentation = "https://docs.rs/serde"
|
documentation = "https://docs.rs/serde"
|
||||||
|
edition = "2021"
|
||||||
homepage = "https://serde.rs"
|
homepage = "https://serde.rs"
|
||||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
keywords = ["serde", "serialization", "no_std"]
|
keywords = ["serde", "serialization", "no_std"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
readme = "crates-io.md"
|
readme = "crates-io.md"
|
||||||
repository = "https://github.com/serde-rs/serde"
|
repository = "https://github.com/serde-rs/serde"
|
||||||
rust-version = "1.19"
|
rust-version = "1.56"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_derive = { version = "=1.0.165", optional = true, path = "../serde_derive" }
|
serde_core = { version = "=1.0.228", path = "../serde_core", default-features = false, features = ["result"] }
|
||||||
|
serde_derive = { version = "1", optional = true, path = "../serde_derive" }
|
||||||
[dev-dependencies]
|
|
||||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[package.metadata.playground]
|
[package.metadata.playground]
|
||||||
features = ["derive", "rc"]
|
features = ["derive", "rc"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["derive"]
|
features = ["derive", "rc", "unstable"]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
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",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
### FEATURES #################################################################
|
### FEATURES #################################################################
|
||||||
@@ -41,20 +43,20 @@ derive = ["serde_derive"]
|
|||||||
|
|
||||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||||
# Requires a dependency on the Rust standard library.
|
# Requires a dependency on the Rust standard library.
|
||||||
std = []
|
std = ["serde_core/std"]
|
||||||
|
|
||||||
# Provide impls for types that require unstable functionality. For tracking and
|
# Provide impls for types that require unstable functionality. For tracking and
|
||||||
# discussion of unstable functionality please refer to this issue:
|
# discussion of unstable functionality please refer to this issue:
|
||||||
#
|
#
|
||||||
# https://github.com/serde-rs/serde/issues/812
|
# 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
|
# 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
|
# 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.
|
# 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
|
# 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.
|
# 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.
|
# Be sure that this is what you want before enabling this feature.
|
||||||
rc = []
|
rc = ["serde_core/rc"]
|
||||||
|
|||||||
+41
-124
@@ -1,6 +1,17 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
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
|
// 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
|
// opening a GitHub issue if your build environment requires some way to enable
|
||||||
@@ -8,145 +19,51 @@ use std::str::{self, FromStr};
|
|||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
println!("cargo:rustc-cfg=if_docsrs_then_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() {
|
let minor = match rustc_minor_version() {
|
||||||
Some(minor) => minor,
|
Some(minor) => minor,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let target = env::var("TARGET").unwrap();
|
if minor >= 77 {
|
||||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
println!("cargo:rustc-check-cfg=cfg(feature, values(\"result\"))");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(if_docsrs_then_no_serde_core)");
|
||||||
// std::collections::Bound was stabilized in Rust 1.17
|
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
||||||
// but it was moved to core::ops later in Rust 1.26:
|
println!("cargo:rustc-check-cfg=cfg(no_core_error)");
|
||||||
// https://doc.rust-lang.org/core/ops/enum.Bound.html
|
println!("cargo:rustc-check-cfg=cfg(no_core_net)");
|
||||||
if minor < 26 {
|
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
||||||
println!("cargo:rustc-cfg=no_ops_bound");
|
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
||||||
if minor < 17 {
|
println!("cargo:rustc-check-cfg=cfg(no_serde_derive)");
|
||||||
println!("cargo:rustc-cfg=no_collections_bound");
|
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)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// core::cmp::Reverse stabilized in Rust 1.19:
|
// Current minimum supported version of serde_derive crate is Rust 1.61.
|
||||||
// https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html
|
if minor < 61 {
|
||||||
if minor < 19 {
|
|
||||||
println!("cargo:rustc-cfg=no_core_reverse");
|
|
||||||
}
|
|
||||||
|
|
||||||
// CString::into_boxed_c_str and PathBuf::into_boxed_path stabilized in Rust 1.20:
|
|
||||||
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
|
|
||||||
// https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.into_boxed_path
|
|
||||||
if minor < 20 {
|
|
||||||
println!("cargo:rustc-cfg=no_de_boxed_c_str");
|
|
||||||
println!("cargo:rustc-cfg=no_de_boxed_path");
|
|
||||||
}
|
|
||||||
|
|
||||||
// From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
|
|
||||||
// https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
|
|
||||||
// https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
|
|
||||||
if minor < 21 {
|
|
||||||
println!("cargo:rustc-cfg=no_de_rc_dst");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration available in core since Rust 1.25:
|
|
||||||
// https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations
|
|
||||||
if minor < 25 {
|
|
||||||
println!("cargo:rustc-cfg=no_core_duration");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 128-bit integers stabilized in Rust 1.26:
|
|
||||||
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
|
|
||||||
//
|
|
||||||
// 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 minor < 26 || emscripten && minor < 40 {
|
|
||||||
println!("cargo:rustc-cfg=no_integer128");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inclusive ranges methods stabilized in Rust 1.27:
|
|
||||||
// https://github.com/rust-lang/rust/pull/50758
|
|
||||||
// Also Iterator::try_for_each:
|
|
||||||
// https://blog.rust-lang.org/2018/06/21/Rust-1.27.html#library-stabilizations
|
|
||||||
if minor < 27 {
|
|
||||||
println!("cargo:rustc-cfg=no_range_inclusive");
|
|
||||||
println!("cargo:rustc-cfg=no_iterator_try_fold");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-zero integers stabilized in Rust 1.28:
|
|
||||||
// https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations
|
|
||||||
if minor < 28 {
|
|
||||||
println!("cargo:rustc-cfg=no_num_nonzero");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current minimum supported version of serde_derive crate is Rust 1.56.
|
|
||||||
if minor < 56 {
|
|
||||||
println!("cargo:rustc-cfg=no_serde_derive");
|
println!("cargo:rustc-cfg=no_serde_derive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
|
// Support for the `#[diagnostic]` tool attribute namespace
|
||||||
if minor < 60 {
|
// https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html#diagnostic-attributes
|
||||||
println!("cargo:rustc-cfg=no_target_has_atomic");
|
if minor < 78 {
|
||||||
// Allowlist of archs that support std::sync::atomic module. This is
|
println!("cargo:rustc-cfg=no_diagnostic_namespace");
|
||||||
// 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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_minor_version() -> Option<u32> {
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
let rustc = match env::var_os("RUSTC") {
|
let rustc = env::var_os("RUSTC")?;
|
||||||
Some(rustc) => rustc,
|
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||||
None => return None,
|
let version = str::from_utf8(&output.stdout).ok()?;
|
||||||
};
|
|
||||||
|
|
||||||
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 mut pieces = version.split('.');
|
let mut pieces = version.split('.');
|
||||||
if pieces.next() != Some("rustc 1") {
|
if pieces.next() != Some("rustc 1") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
pieces.next()?.parse().ok()
|
||||||
let next = match pieces.next() {
|
|
||||||
Some(next) => next,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
u32::from_str(next).ok()
|
|
||||||
}
|
}
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../serde_core/src
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
use lib::*;
|
|
||||||
|
|
||||||
const TAG_CONT: u8 = 0b1000_0000;
|
|
||||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
|
||||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
|
||||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
|
||||||
const MAX_ONE_B: u32 = 0x80;
|
|
||||||
const MAX_TWO_B: u32 = 0x800;
|
|
||||||
const MAX_THREE_B: u32 = 0x10000;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn encode(c: char) -> Encode {
|
|
||||||
let code = c as u32;
|
|
||||||
let mut buf = [0; 4];
|
|
||||||
let pos = if code < MAX_ONE_B {
|
|
||||||
buf[3] = code as u8;
|
|
||||||
3
|
|
||||||
} else if code < MAX_TWO_B {
|
|
||||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
|
||||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
|
||||||
2
|
|
||||||
} else if code < MAX_THREE_B {
|
|
||||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
|
||||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
|
||||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
|
||||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
|
||||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
|
||||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
|
||||||
0
|
|
||||||
};
|
|
||||||
Encode { buf, pos }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Encode {
|
|
||||||
buf: [u8; 4],
|
|
||||||
pos: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Encode {
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
str::from_utf8(&self.buf[self.pos..]).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+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.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// macro_rules! serde_if_integer128 {
|
|
||||||
/// ($($tt:tt)*) => {
|
|
||||||
/// $($tt)*
|
|
||||||
/// };
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// When built without support for 128-bit integers, this macro expands to
|
|
||||||
/// nothing.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// macro_rules! serde_if_integer128 {
|
|
||||||
/// ($($tt:tt)*) => {};
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[cfg(not(no_integer128))]
|
|
||||||
#[macro_export]
|
#[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 {
|
macro_rules! serde_if_integer128 {
|
||||||
($($tt:tt)*) => {
|
($($tt:tt)*) => {
|
||||||
$($tt)*
|
$($tt)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(no_integer128)]
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! serde_if_integer128 {
|
|
||||||
($($tt:tt)*) => {};
|
|
||||||
}
|
|
||||||
|
|||||||
+158
-222
@@ -9,7 +9,7 @@
|
|||||||
//! these two groups interact with each other, allowing any supported data
|
//! these two groups interact with each other, allowing any supported data
|
||||||
//! structure to be serialized and deserialized using any supported data format.
|
//! 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.
|
//! usage examples.
|
||||||
//!
|
//!
|
||||||
//! ## Design
|
//! ## Design
|
||||||
@@ -63,6 +63,7 @@
|
|||||||
//! and from DynamoDB.
|
//! and from DynamoDB.
|
||||||
//! - [Hjson], a syntax extension to JSON designed around human reading and
|
//! - [Hjson], a syntax extension to JSON designed around human reading and
|
||||||
//! editing. *(deserialization only)*
|
//! editing. *(deserialization only)*
|
||||||
|
//! - [CSV], Comma-separated values is a tabular text file format.
|
||||||
//!
|
//!
|
||||||
//! [JSON]: https://github.com/serde-rs/json
|
//! [JSON]: https://github.com/serde-rs/json
|
||||||
//! [Postcard]: https://github.com/jamesmunns/postcard
|
//! [Postcard]: https://github.com/jamesmunns/postcard
|
||||||
@@ -89,66 +90,76 @@
|
|||||||
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
|
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
|
||||||
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb
|
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb
|
||||||
//! [Hjson]: https://github.com/Canop/deser-hjson
|
//! [Hjson]: https://github.com/Canop/deser-hjson
|
||||||
|
//! [CSV]: https://docs.rs/csv
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Serde types in rustdoc of other crates get linked to here.
|
// Serde types in rustdoc of other crates get linked to here.
|
||||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.165")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.228")]
|
||||||
// Support using Serde without the standard library!
|
// Support using Serde without the standard library!
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![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
|
// Unstable functionality only if the user asks for it. For tracking and
|
||||||
// discussion of these features please refer to this issue:
|
// discussion of these features please refer to this issue:
|
||||||
//
|
//
|
||||||
// https://github.com/serde-rs/serde/issues/812
|
// https://github.com/serde-rs/serde/issues/812
|
||||||
#![cfg_attr(feature = "unstable", feature(error_in_core, never_type))]
|
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
#![allow(
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
unknown_lints,
|
||||||
// Ignored clippy and clippy_pedantic lints
|
bare_trait_objects,
|
||||||
#![cfg_attr(
|
deprecated,
|
||||||
feature = "cargo-clippy",
|
mismatched_lifetime_syntaxes
|
||||||
allow(
|
|
||||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
|
||||||
unnested_or_patterns,
|
|
||||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
|
|
||||||
semicolon_if_nothing_returned,
|
|
||||||
// not available in our oldest supported compiler
|
|
||||||
empty_enum,
|
|
||||||
type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
|
||||||
// integer and float ser/de requires these sorts of casts
|
|
||||||
cast_possible_truncation,
|
|
||||||
cast_possible_wrap,
|
|
||||||
cast_sign_loss,
|
|
||||||
// things are often more readable this way
|
|
||||||
cast_lossless,
|
|
||||||
module_name_repetitions,
|
|
||||||
option_if_let_else,
|
|
||||||
single_match_else,
|
|
||||||
type_complexity,
|
|
||||||
use_self,
|
|
||||||
zero_prefixed_literal,
|
|
||||||
// correctly used
|
|
||||||
derive_partial_eq_without_eq,
|
|
||||||
enum_glob_use,
|
|
||||||
explicit_auto_deref,
|
|
||||||
let_underscore_untyped,
|
|
||||||
map_err_ignore,
|
|
||||||
new_without_default,
|
|
||||||
result_unit_err,
|
|
||||||
wildcard_imports,
|
|
||||||
// not practical
|
|
||||||
needless_pass_by_value,
|
|
||||||
similar_names,
|
|
||||||
too_many_lines,
|
|
||||||
// preference
|
|
||||||
doc_markdown,
|
|
||||||
unseparated_literal_suffix,
|
|
||||||
// false positive
|
|
||||||
needless_doctest_main,
|
|
||||||
// noisy
|
|
||||||
missing_errors_doc,
|
|
||||||
must_use_candidate,
|
|
||||||
)
|
|
||||||
)]
|
)]
|
||||||
|
// 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.
|
// Rustc lints.
|
||||||
#![deny(missing_docs, unused_imports)]
|
#![deny(missing_docs, unused_imports)]
|
||||||
|
|
||||||
@@ -157,193 +168,118 @@
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
// Rustdoc has a lot of shortcomings related to cross-crate re-exports that make
|
||||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
// the rendered documentation of serde_core traits in serde more challenging to
|
||||||
/// module.
|
// understand than the equivalent documentation of the same items in serde_core.
|
||||||
mod lib {
|
// https://github.com/rust-lang/rust/labels/A-cross-crate-reexports
|
||||||
mod core {
|
// So, just for the purpose of docs.rs documentation, we inline the contents of
|
||||||
#[cfg(not(feature = "std"))]
|
// serde_core into serde. This sidesteps all the cross-crate rustdoc bugs.
|
||||||
pub use core::*;
|
#[cfg(docsrs)]
|
||||||
#[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::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::Range;
|
|
||||||
pub use self::core::option::{self, Option};
|
|
||||||
pub use self::core::result::{self, 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;
|
|
||||||
|
|
||||||
#[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 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", not(no_collections_bound), no_ops_bound))]
|
|
||||||
pub use std::collections::Bound;
|
|
||||||
|
|
||||||
#[cfg(not(no_core_reverse))]
|
|
||||||
pub use self::core::cmp::Reverse;
|
|
||||||
|
|
||||||
#[cfg(not(no_ops_bound))]
|
|
||||||
pub use self::core::ops::Bound;
|
|
||||||
|
|
||||||
#[cfg(not(no_range_inclusive))]
|
|
||||||
pub use self::core::ops::RangeInclusive;
|
|
||||||
|
|
||||||
#[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(any(feature = "std", not(no_core_duration)))]
|
|
||||||
pub use self::core::time::Duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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! try {
|
|
||||||
($expr:expr) => {
|
|
||||||
match $expr {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
#[path = "core/crate_root.rs"]
|
||||||
|
mod crate_root;
|
||||||
|
|
||||||
|
#[cfg(docsrs)]
|
||||||
|
#[macro_use]
|
||||||
|
#[path = "core/macros.rs"]
|
||||||
mod macros;
|
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;
|
mod integer128;
|
||||||
|
|
||||||
pub mod de;
|
|
||||||
pub mod ser;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use de::{Deserialize, Deserializer};
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use ser::{Serialize, Serializer};
|
|
||||||
|
|
||||||
// Used by generated code and doc tests. Not public API.
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[path = "private/mod.rs"]
|
|
||||||
pub mod __private;
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use self::__private as export;
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use self::__private as private;
|
|
||||||
|
|
||||||
#[path = "de/seed.rs"]
|
|
||||||
mod seed;
|
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
|
||||||
mod std_error;
|
|
||||||
|
|
||||||
// Re-export #[derive(Serialize, Deserialize)].
|
// Re-export #[derive(Serialize, Deserialize)].
|
||||||
//
|
//
|
||||||
// The reason re-exporting is not enabled by default is that disabling it would
|
// The reason re-exporting is not enabled by default is that disabling it would
|
||||||
// be annoying for crates that provide handwritten impls or data formats. They
|
// be annoying for crates that provide handwritten impls or data formats. They
|
||||||
// would need to disable default features and then explicitly re-enable std.
|
// would need to disable default features and then explicitly re-enable std.
|
||||||
#[cfg(feature = "serde_derive")]
|
#[cfg(feature = "serde_derive")]
|
||||||
#[allow(unused_imports)]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
/// Derive macro available if serde is built with `features = ["derive"]`.
|
/// Derive macro available if serde is built with `features = ["derive"]`.
|
||||||
#[cfg(feature = "serde_derive")]
|
#[cfg(feature = "serde_derive")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||||
pub use serde_derive::{Deserialize, Serialize};
|
pub use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
#[macro_export]
|
||||||
mod actually_private {
|
#[doc(hidden)]
|
||||||
pub struct T;
|
macro_rules! __require_serde_not_serde_core {
|
||||||
|
() => {};
|
||||||
}
|
}
|
||||||
|
|||||||
+1053
-505
File diff suppressed because it is too large
Load Diff
+10
-42
@@ -3,48 +3,16 @@ pub mod de;
|
|||||||
#[cfg(not(no_serde_derive))]
|
#[cfg(not(no_serde_derive))]
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
|
|
||||||
pub mod size_hint;
|
pub use crate::lib::clone::Clone;
|
||||||
|
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;
|
||||||
|
pub use crate::lib::option::Option::{self, None, Some};
|
||||||
|
pub use crate::lib::ptr;
|
||||||
|
pub use crate::lib::result::Result::{self, Err, Ok};
|
||||||
|
|
||||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
pub use crate::serde_core_private::string::from_utf8_lossy;
|
||||||
pub mod doc;
|
|
||||||
|
|
||||||
pub use lib::clone::Clone;
|
|
||||||
pub use lib::convert::{From, Into};
|
|
||||||
pub use lib::default::Default;
|
|
||||||
pub use lib::fmt::{self, Formatter};
|
|
||||||
pub use lib::marker::PhantomData;
|
|
||||||
pub use lib::option::Option::{self, None, Some};
|
|
||||||
pub use lib::ptr;
|
|
||||||
pub use lib::result::Result::{self, Err, Ok};
|
|
||||||
|
|
||||||
pub use self::string::from_utf8_lossy;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub use lib::{ToString, Vec};
|
pub use crate::lib::{ToString, Vec};
|
||||||
|
|
||||||
#[cfg(not(no_core_try_from))]
|
|
||||||
pub use lib::convert::TryFrom;
|
|
||||||
|
|
||||||
mod string {
|
|
||||||
use 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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+220
-148
@@ -1,6 +1,6 @@
|
|||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
|
use crate::ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use self::content::{
|
use self::content::{
|
||||||
@@ -51,14 +51,14 @@ enum Unsupported {
|
|||||||
String,
|
String,
|
||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
UnitStruct,
|
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||||
Enum,
|
Enum,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl Display for Unsupported {
|
impl Display for Unsupported {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
@@ -69,11 +69,10 @@ impl Display for Unsupported {
|
|||||||
Unsupported::String => formatter.write_str("a string"),
|
Unsupported::String => formatter.write_str("a string"),
|
||||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||||
Unsupported::Optional => formatter.write_str("an optional"),
|
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::Sequence => formatter.write_str("a sequence"),
|
||||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||||
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||||
Unsupported::Enum => formatter.write_str("an enum"),
|
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>
|
impl<S> Serializer for TaggedSerializer<S>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
@@ -174,22 +174,22 @@ where
|
|||||||
Err(self.bad_type(Unsupported::Optional))
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Err(self.bad_type(Unsupported::Optional))
|
Err(self.bad_type(Unsupported::Optional))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(1)));
|
let mut map = tri!(self.delegate.serialize_map(Some(1)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(1)));
|
let mut map = tri!(self.delegate.serialize_map(Some(1)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,24 +199,24 @@ where
|
|||||||
_: u32,
|
_: u32,
|
||||||
inner_variant: &'static str,
|
inner_variant: &'static str,
|
||||||
) -> Result<Self::Ok, Self::Error> {
|
) -> Result<Self::Ok, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
let mut map = tri!(self.delegate.serialize_map(Some(2)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
try!(map.serialize_entry(inner_variant, &()));
|
tri!(map.serialize_entry(inner_variant, &()));
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_struct<T: ?Sized>(
|
fn serialize_newtype_struct<T>(
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Self::Ok, Self::Error>
|
) -> Result<Self::Ok, Self::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
fn serialize_newtype_variant<T>(
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
@@ -224,11 +224,11 @@ where
|
|||||||
inner_value: &T,
|
inner_value: &T,
|
||||||
) -> Result<Self::Ok, Self::Error>
|
) -> Result<Self::Ok, Self::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
let mut map = tri!(self.delegate.serialize_map(Some(2)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
try!(map.serialize_entry(inner_variant, inner_value));
|
tri!(map.serialize_entry(inner_variant, inner_value));
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,9 +269,9 @@ where
|
|||||||
inner_variant: &'static str,
|
inner_variant: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
let mut map = tri!(self.delegate.serialize_map(Some(2)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
try!(map.serialize_key(inner_variant));
|
tri!(map.serialize_key(inner_variant));
|
||||||
Ok(SerializeTupleVariantAsMapValue::new(
|
Ok(SerializeTupleVariantAsMapValue::new(
|
||||||
map,
|
map,
|
||||||
inner_variant,
|
inner_variant,
|
||||||
@@ -280,8 +280,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
|
let mut map = tri!(self.delegate.serialize_map(len.map(|len| len + 1)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,8 +290,8 @@ where
|
|||||||
name: &'static str,
|
name: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
let mut state = try!(self.delegate.serialize_struct(name, len + 1));
|
let mut state = tri!(self.delegate.serialize_struct(name, len + 1));
|
||||||
try!(state.serialize_field(self.tag, self.variant_name));
|
tri!(state.serialize_field(self.tag, self.variant_name));
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,9 +316,9 @@ where
|
|||||||
inner_variant: &'static str,
|
inner_variant: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
let mut map = tri!(self.delegate.serialize_map(Some(2)));
|
||||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
try!(map.serialize_key(inner_variant));
|
tri!(map.serialize_key(inner_variant));
|
||||||
Ok(SerializeStructVariantAsMapValue::new(
|
Ok(SerializeStructVariantAsMapValue::new(
|
||||||
map,
|
map,
|
||||||
inner_variant,
|
inner_variant,
|
||||||
@@ -327,9 +327,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
#[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
|
where
|
||||||
T: Display,
|
T: ?Sized + Display,
|
||||||
{
|
{
|
||||||
Err(self.bad_type(Unsupported::String))
|
Err(self.bad_type(Unsupported::String))
|
||||||
}
|
}
|
||||||
@@ -337,9 +337,9 @@ where
|
|||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
mod content {
|
mod content {
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use ser::{self, Serialize, Serializer};
|
use crate::ser::{self, Serialize, Serializer};
|
||||||
|
|
||||||
pub struct SerializeTupleVariantAsMapValue<M> {
|
pub struct SerializeTupleVariantAsMapValue<M> {
|
||||||
map: M,
|
map: M,
|
||||||
@@ -357,6 +357,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
|
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
|
||||||
where
|
where
|
||||||
M: ser::SerializeMap,
|
M: ser::SerializeMap,
|
||||||
@@ -364,17 +365,17 @@ mod content {
|
|||||||
type Ok = M::Ok;
|
type Ok = M::Ok;
|
||||||
type Error = M::Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||||
self.fields.push(value);
|
self.fields.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||||
try!(self
|
tri!(self
|
||||||
.map
|
.map
|
||||||
.serialize_value(&Content::TupleStruct(self.name, self.fields)));
|
.serialize_value(&Content::TupleStruct(self.name, self.fields)));
|
||||||
self.map.end()
|
self.map.end()
|
||||||
@@ -397,6 +398,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
|
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
|
||||||
where
|
where
|
||||||
M: ser::SerializeMap,
|
M: ser::SerializeMap,
|
||||||
@@ -404,21 +406,17 @@ mod content {
|
|||||||
type Ok = M::Ok;
|
type Ok = M::Ok;
|
||||||
type Error = M::Error;
|
type Error = M::Error;
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), M::Error>
|
||||||
&mut self,
|
|
||||||
key: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), M::Error>
|
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||||
self.fields.push((key, value));
|
self.fields.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||||
try!(self
|
tri!(self
|
||||||
.map
|
.map
|
||||||
.serialize_value(&Content::Struct(self.name, self.fields)));
|
.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||||
self.map.end()
|
self.map.end()
|
||||||
@@ -468,6 +466,7 @@ mod content {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl Serialize for Content {
|
impl Serialize for Content {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -499,50 +498,50 @@ mod content {
|
|||||||
}
|
}
|
||||||
Content::Seq(ref elements) => elements.serialize(serializer),
|
Content::Seq(ref elements) => elements.serialize(serializer),
|
||||||
Content::Tuple(ref elements) => {
|
Content::Tuple(ref elements) => {
|
||||||
use ser::SerializeTuple;
|
use crate::ser::SerializeTuple;
|
||||||
let mut tuple = try!(serializer.serialize_tuple(elements.len()));
|
let mut tuple = tri!(serializer.serialize_tuple(elements.len()));
|
||||||
for e in elements {
|
for e in elements {
|
||||||
try!(tuple.serialize_element(e));
|
tri!(tuple.serialize_element(e));
|
||||||
}
|
}
|
||||||
tuple.end()
|
tuple.end()
|
||||||
}
|
}
|
||||||
Content::TupleStruct(n, ref fields) => {
|
Content::TupleStruct(n, ref fields) => {
|
||||||
use ser::SerializeTupleStruct;
|
use crate::ser::SerializeTupleStruct;
|
||||||
let mut ts = try!(serializer.serialize_tuple_struct(n, fields.len()));
|
let mut ts = tri!(serializer.serialize_tuple_struct(n, fields.len()));
|
||||||
for f in fields {
|
for f in fields {
|
||||||
try!(ts.serialize_field(f));
|
tri!(ts.serialize_field(f));
|
||||||
}
|
}
|
||||||
ts.end()
|
ts.end()
|
||||||
}
|
}
|
||||||
Content::TupleVariant(n, i, v, ref fields) => {
|
Content::TupleVariant(n, i, v, ref fields) => {
|
||||||
use ser::SerializeTupleVariant;
|
use crate::ser::SerializeTupleVariant;
|
||||||
let mut tv = try!(serializer.serialize_tuple_variant(n, i, v, fields.len()));
|
let mut tv = tri!(serializer.serialize_tuple_variant(n, i, v, fields.len()));
|
||||||
for f in fields {
|
for f in fields {
|
||||||
try!(tv.serialize_field(f));
|
tri!(tv.serialize_field(f));
|
||||||
}
|
}
|
||||||
tv.end()
|
tv.end()
|
||||||
}
|
}
|
||||||
Content::Map(ref entries) => {
|
Content::Map(ref entries) => {
|
||||||
use ser::SerializeMap;
|
use crate::ser::SerializeMap;
|
||||||
let mut map = try!(serializer.serialize_map(Some(entries.len())));
|
let mut map = tri!(serializer.serialize_map(Some(entries.len())));
|
||||||
for (k, v) in entries {
|
for (k, v) in entries {
|
||||||
try!(map.serialize_entry(k, v));
|
tri!(map.serialize_entry(k, v));
|
||||||
}
|
}
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
Content::Struct(n, ref fields) => {
|
Content::Struct(n, ref fields) => {
|
||||||
use ser::SerializeStruct;
|
use crate::ser::SerializeStruct;
|
||||||
let mut s = try!(serializer.serialize_struct(n, fields.len()));
|
let mut s = tri!(serializer.serialize_struct(n, fields.len()));
|
||||||
for &(k, ref v) in fields {
|
for &(k, ref v) in fields {
|
||||||
try!(s.serialize_field(k, v));
|
tri!(s.serialize_field(k, v));
|
||||||
}
|
}
|
||||||
s.end()
|
s.end()
|
||||||
}
|
}
|
||||||
Content::StructVariant(n, i, v, ref fields) => {
|
Content::StructVariant(n, i, v, ref fields) => {
|
||||||
use ser::SerializeStructVariant;
|
use crate::ser::SerializeStructVariant;
|
||||||
let mut sv = try!(serializer.serialize_struct_variant(n, i, v, fields.len()));
|
let mut sv = tri!(serializer.serialize_struct_variant(n, i, v, fields.len()));
|
||||||
for &(k, ref v) in fields {
|
for &(k, ref v) in fields {
|
||||||
try!(sv.serialize_field(k, v));
|
tri!(sv.serialize_field(k, v));
|
||||||
}
|
}
|
||||||
sv.end()
|
sv.end()
|
||||||
}
|
}
|
||||||
@@ -560,6 +559,7 @@ mod content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> Serializer for ContentSerializer<E>
|
impl<E> Serializer for ContentSerializer<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -635,11 +635,11 @@ mod content {
|
|||||||
Ok(Content::None)
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Ok(Content::Some(Box::new(try!(value.serialize(self)))))
|
Ok(Content::Some(Box::new(tri!(value.serialize(self)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<Content, E> {
|
fn serialize_unit(self) -> Result<Content, E> {
|
||||||
@@ -659,21 +659,17 @@ mod content {
|
|||||||
Ok(Content::UnitVariant(name, variant_index, variant))
|
Ok(Content::UnitVariant(name, variant_index, variant))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_struct<T: ?Sized>(
|
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Content, E>
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<Content, E>
|
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Ok(Content::NewtypeStruct(
|
Ok(Content::NewtypeStruct(
|
||||||
name,
|
name,
|
||||||
Box::new(try!(value.serialize(self))),
|
Box::new(tri!(value.serialize(self))),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
fn serialize_newtype_variant<T>(
|
||||||
self,
|
self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
@@ -681,13 +677,13 @@ mod content {
|
|||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Content, E>
|
) -> Result<Content, E>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Ok(Content::NewtypeVariant(
|
Ok(Content::NewtypeVariant(
|
||||||
name,
|
name,
|
||||||
variant_index,
|
variant_index,
|
||||||
variant,
|
variant,
|
||||||
Box::new(try!(value.serialize(self))),
|
Box::new(tri!(value.serialize(self))),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -775,6 +771,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeSeq for SerializeSeq<E>
|
impl<E> ser::SerializeSeq for SerializeSeq<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -782,11 +779,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.elements.push(value);
|
self.elements.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -801,6 +798,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeTuple for SerializeTuple<E>
|
impl<E> ser::SerializeTuple for SerializeTuple<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -808,11 +806,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.elements.push(value);
|
self.elements.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -828,6 +826,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
|
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -835,11 +834,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.fields.push(value);
|
self.fields.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -857,6 +856,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
|
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -864,11 +864,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.fields.push(value);
|
self.fields.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -889,6 +889,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeMap for SerializeMap<E>
|
impl<E> ser::SerializeMap for SerializeMap<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -896,24 +897,24 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let key = try!(key.serialize(ContentSerializer::<E>::new()));
|
let key = tri!(key.serialize(ContentSerializer::<E>::new()));
|
||||||
self.key = Some(key);
|
self.key = Some(key);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), E>
|
fn serialize_value<T>(&mut self, value: &T) -> Result<(), E>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let key = self
|
let key = self
|
||||||
.key
|
.key
|
||||||
.take()
|
.take()
|
||||||
.expect("serialize_value called before serialize_key");
|
.expect("serialize_value called before serialize_key");
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.entries.push((key, value));
|
self.entries.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -922,13 +923,13 @@ mod content {
|
|||||||
Ok(Content::Map(self.entries))
|
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
|
where
|
||||||
K: Serialize,
|
K: ?Sized + Serialize,
|
||||||
V: Serialize,
|
V: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let key = try!(key.serialize(ContentSerializer::<E>::new()));
|
let key = tri!(key.serialize(ContentSerializer::<E>::new()));
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.entries.push((key, value));
|
self.entries.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -940,6 +941,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeStruct for SerializeStruct<E>
|
impl<E> ser::SerializeStruct for SerializeStruct<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -947,11 +949,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.fields.push((key, value));
|
self.fields.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -969,6 +971,7 @@ mod content {
|
|||||||
error: PhantomData<E>,
|
error: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
|
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
|
||||||
where
|
where
|
||||||
E: ser::Error,
|
E: ser::Error,
|
||||||
@@ -976,11 +979,11 @@ mod content {
|
|||||||
type Ok = Content;
|
type Ok = Content;
|
||||||
type Error = E;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<E>::new()));
|
||||||
self.fields.push((key, value));
|
self.fields.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1013,6 +1016,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
|
impl<'a, M> Serializer for FlatMapSerializer<'a, M>
|
||||||
where
|
where
|
||||||
M: SerializeMap + 'a,
|
M: SerializeMap + 'a,
|
||||||
@@ -1025,7 +1029,7 @@ where
|
|||||||
type SerializeTupleStruct = Impossible<Self::Ok, M::Error>;
|
type SerializeTupleStruct = Impossible<Self::Ok, M::Error>;
|
||||||
type SerializeMap = FlatMapSerializeMap<'a, M>;
|
type SerializeMap = FlatMapSerializeMap<'a, M>;
|
||||||
type SerializeStruct = FlatMapSerializeStruct<'a, M>;
|
type SerializeStruct = FlatMapSerializeStruct<'a, M>;
|
||||||
type SerializeTupleVariant = Impossible<Self::Ok, M::Error>;
|
type SerializeTupleVariant = FlatMapSerializeTupleVariantAsMapValue<'a, M>;
|
||||||
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
|
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
|
||||||
|
|
||||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||||
@@ -1088,9 +1092,9 @@ where
|
|||||||
Ok(())
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
@@ -1100,30 +1104,30 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(Self::bad_type(Unsupported::UnitStruct))
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
_: &'static str,
|
variant: &'static str,
|
||||||
) -> Result<Self::Ok, Self::Error> {
|
) -> 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,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Self::Ok, Self::Error>
|
) -> Result<Self::Ok, Self::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
fn serialize_newtype_variant<T>(
|
||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
@@ -1131,10 +1135,9 @@ where
|
|||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Self::Ok, Self::Error>
|
) -> Result<Self::Ok, Self::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
try!(self.0.serialize_key(variant));
|
self.0.serialize_entry(variant, value)
|
||||||
self.0.serialize_value(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
@@ -1157,10 +1160,11 @@ where
|
|||||||
self,
|
self,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: u32,
|
_: u32,
|
||||||
_: &'static str,
|
variant: &'static str,
|
||||||
_: usize,
|
_: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||||
Err(Self::bad_type(Unsupported::Enum))
|
tri!(self.0.serialize_key(variant));
|
||||||
|
Ok(FlatMapSerializeTupleVariantAsMapValue::new(self.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
@@ -1182,7 +1186,7 @@ where
|
|||||||
inner_variant: &'static str,
|
inner_variant: &'static str,
|
||||||
_: usize,
|
_: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
try!(self.0.serialize_key(inner_variant));
|
tri!(self.0.serialize_key(inner_variant));
|
||||||
Ok(FlatMapSerializeStructVariantAsMapValue::new(
|
Ok(FlatMapSerializeStructVariantAsMapValue::new(
|
||||||
self.0,
|
self.0,
|
||||||
inner_variant,
|
inner_variant,
|
||||||
@@ -1194,6 +1198,7 @@ where
|
|||||||
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
|
pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M);
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M>
|
||||||
where
|
where
|
||||||
M: SerializeMap + 'a,
|
M: SerializeMap + 'a,
|
||||||
@@ -1201,28 +1206,24 @@ where
|
|||||||
type Ok = ();
|
type Ok = ();
|
||||||
type Error = M::Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.0.serialize_key(key)
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.0.serialize_value(value)
|
self.0.serialize_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
|
||||||
&mut self,
|
|
||||||
key: &K,
|
|
||||||
value: &V,
|
|
||||||
) -> Result<(), Self::Error>
|
|
||||||
where
|
where
|
||||||
K: Serialize,
|
K: ?Sized + Serialize,
|
||||||
V: Serialize,
|
V: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.0.serialize_entry(key, value)
|
self.0.serialize_entry(key, value)
|
||||||
}
|
}
|
||||||
@@ -1236,6 +1237,7 @@ where
|
|||||||
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
|
pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M);
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
|
||||||
where
|
where
|
||||||
M: SerializeMap + 'a,
|
M: SerializeMap + 'a,
|
||||||
@@ -1243,13 +1245,9 @@ where
|
|||||||
type Ok = ();
|
type Ok = ();
|
||||||
type Error = M::Error;
|
type Error = M::Error;
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||||
&mut self,
|
|
||||||
key: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Self::Error>
|
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.0.serialize_entry(key, value)
|
self.0.serialize_entry(key, value)
|
||||||
}
|
}
|
||||||
@@ -1259,6 +1257,53 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub struct FlatMapSerializeTupleVariantAsMapValue<'a, M: 'a> {
|
||||||
|
map: &'a mut M,
|
||||||
|
fields: Vec<Content>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, M> FlatMapSerializeTupleVariantAsMapValue<'a, M>
|
||||||
|
where
|
||||||
|
M: SerializeMap + 'a,
|
||||||
|
{
|
||||||
|
fn new(map: &'a mut M) -> Self {
|
||||||
|
FlatMapSerializeTupleVariantAsMapValue {
|
||||||
|
map,
|
||||||
|
fields: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = M::Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||||
|
self.fields.push(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
|
tri!(self.map.serialize_value(&Content::Seq(self.fields)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
|
pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
|
||||||
map: &'a mut M,
|
map: &'a mut M,
|
||||||
@@ -1281,6 +1326,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
|
||||||
where
|
where
|
||||||
M: SerializeMap + 'a,
|
M: SerializeMap + 'a,
|
||||||
@@ -1288,23 +1334,49 @@ where
|
|||||||
type Ok = ();
|
type Ok = ();
|
||||||
type Error = M::Error;
|
type Error = M::Error;
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
|
||||||
&mut self,
|
|
||||||
key: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Self::Error>
|
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
let value = tri!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||||
self.fields.push((key, value));
|
self.fields.push((key, value));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<(), Self::Error> {
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
try!(self
|
tri!(self
|
||||||
.map
|
.map
|
||||||
.serialize_value(&Content::Struct(self.name, self.fields)));
|
.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AdjacentlyTaggedEnumVariant {
|
||||||
|
pub enum_name: &'static str,
|
||||||
|
pub variant_index: u32,
|
||||||
|
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
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error when Serialize for a non_exhaustive remote enum encounters a variant
|
||||||
|
// 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,
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "enum variant cannot be serialized: {:?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
use lib::*;
|
|
||||||
|
|
||||||
pub fn from_bounds<I>(iter: &I) -> Option<usize>
|
|
||||||
where
|
|
||||||
I: Iterator,
|
|
||||||
{
|
|
||||||
helper(iter.size_hint())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
#[inline]
|
|
||||||
pub fn cautious(hint: Option<usize>) -> usize {
|
|
||||||
cmp::min(hint.unwrap_or(0), 4096)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
|
|
||||||
match bounds {
|
|
||||||
(lower, Some(upper)) if lower == upper => Some(upper),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
[package]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
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.228", 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 = []
|
||||||
@@ -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(if_docsrs_then_no_serde_core)");
|
||||||
|
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_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,171 @@
|
|||||||
|
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(all(docsrs, if_docsrs_then_no_serde_core), path = "core/de/mod.rs")]
|
||||||
|
pub mod de;
|
||||||
|
#[cfg_attr(all(docsrs, if_docsrs_then_no_serde_core), path = "core/ser/mod.rs")]
|
||||||
|
pub mod ser;
|
||||||
|
|
||||||
|
#[cfg_attr(all(docsrs, if_docsrs_then_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(
|
||||||
|
all(docsrs, if_docsrs_then_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(all(docsrs, if_docsrs_then_no_serde_core), path = "core/std_error.rs")]
|
||||||
|
mod std_error;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use de::{
|
use crate::de::{
|
||||||
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
|
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -10,13 +10,12 @@ use de::{
|
|||||||
/// any type, except that it does not store any information about the data that
|
/// any type, except that it does not store any information about the data that
|
||||||
/// gets deserialized.
|
/// gets deserialized.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// use std::fmt;
|
|
||||||
/// use std::marker::PhantomData;
|
|
||||||
///
|
|
||||||
/// use serde::de::{
|
/// use serde::de::{
|
||||||
/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor,
|
/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor,
|
||||||
/// };
|
/// };
|
||||||
|
/// use std::fmt;
|
||||||
|
/// use std::marker::PhantomData;
|
||||||
///
|
///
|
||||||
/// /// A seed that can be used to deserialize only the `n`th element of a sequence
|
/// /// A seed that can be used to deserialize only the `n`th element of a sequence
|
||||||
/// /// while efficiently discarding elements of any type before or after index `n`.
|
/// /// while efficiently discarding elements of any type before or after index `n`.
|
||||||
@@ -108,7 +107,7 @@ use de::{
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Copy, Clone, Debug, Default)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct IgnoredAny;
|
pub struct IgnoredAny;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for IgnoredAny {
|
impl<'de> Visitor<'de> for IgnoredAny {
|
||||||
@@ -130,12 +129,10 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_if_integer128! {
|
#[inline]
|
||||||
#[inline]
|
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||||
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
let _ = x;
|
||||||
let _ = x;
|
Ok(IgnoredAny)
|
||||||
Ok(IgnoredAny)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -144,12 +141,10 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_if_integer128! {
|
#[inline]
|
||||||
#[inline]
|
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||||
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
let _ = x;
|
||||||
let _ = x;
|
Ok(IgnoredAny)
|
||||||
Ok(IgnoredAny)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -198,7 +193,7 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
where
|
where
|
||||||
A: SeqAccess<'de>,
|
A: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
while let Some(IgnoredAny) = try!(seq.next_element()) {
|
while let Some(IgnoredAny) = tri!(seq.next_element()) {
|
||||||
// Gobble
|
// Gobble
|
||||||
}
|
}
|
||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
@@ -209,7 +204,7 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
where
|
where
|
||||||
A: MapAccess<'de>,
|
A: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
while let Some((IgnoredAny, IgnoredAny)) = try!(map.next_entry()) {
|
while let Some((IgnoredAny, IgnoredAny)) = tri!(map.next_entry()) {
|
||||||
// Gobble
|
// Gobble
|
||||||
}
|
}
|
||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
@@ -228,7 +223,7 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
where
|
where
|
||||||
A: EnumAccess<'de>,
|
A: EnumAccess<'de>,
|
||||||
{
|
{
|
||||||
try!(data.variant::<IgnoredAny>()).1.newtype_variant()
|
tri!(data.variant::<IgnoredAny>()).1.newtype_variant()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -64,8 +64,8 @@
|
|||||||
//! - RefCell\<T\>
|
//! - RefCell\<T\>
|
||||||
//! - Mutex\<T\>
|
//! - Mutex\<T\>
|
||||||
//! - RwLock\<T\>
|
//! - RwLock\<T\>
|
||||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
//! - Rc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
//! - Arc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||||
//! - **Collection types**:
|
//! - **Collection types**:
|
||||||
//! - BTreeMap\<K, V\>
|
//! - BTreeMap\<K, V\>
|
||||||
//! - BTreeSet\<T\>
|
//! - BTreeSet\<T\>
|
||||||
@@ -101,8 +101,8 @@
|
|||||||
//! - SocketAddrV6
|
//! - SocketAddrV6
|
||||||
//!
|
//!
|
||||||
//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html
|
//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html
|
||||||
//! [`Deserialize`]: ../trait.Deserialize.html
|
//! [`Deserialize`]: crate::Deserialize
|
||||||
//! [`Deserializer`]: ../trait.Deserializer.html
|
//! [`Deserializer`]: crate::Deserializer
|
||||||
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
|
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
|
||||||
//! [`postcard`]: https://github.com/jamesmunns/postcard
|
//! [`postcard`]: https://github.com/jamesmunns/postcard
|
||||||
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
||||||
@@ -112,26 +112,25 @@
|
|||||||
//! [derive section of the manual]: https://serde.rs/derive.html
|
//! [derive section of the manual]: https://serde.rs/derive.html
|
||||||
//! [data formats]: https://serde.rs/#data-formats
|
//! [data formats]: https://serde.rs/#data-formats
|
||||||
|
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
|
||||||
#[cfg(not(no_integer128))]
|
|
||||||
mod format;
|
|
||||||
mod ignored_any;
|
mod ignored_any;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod utf8;
|
|
||||||
|
|
||||||
pub use self::ignored_any::IgnoredAny;
|
pub use self::ignored_any::IgnoredAny;
|
||||||
|
#[cfg(all(not(feature = "std"), no_core_error))]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use crate::std_error::Error as StdError;
|
||||||
|
#[cfg(not(any(feature = "std", no_core_error)))]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use core::error::Error as StdError;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use std::error::Error as StdError;
|
pub use std::error::Error as StdError;
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[doc(no_inline)]
|
|
||||||
pub use std_error::Error as StdError;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -157,12 +156,18 @@ macro_rules! declare_error_trait {
|
|||||||
/// type appropriate for a basic JSON data format.
|
/// type appropriate for a basic JSON data format.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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)::+)* {
|
pub trait Error: Sized $(+ $($supertrait)::+)* {
|
||||||
/// Raised when there is general error when deserializing a type.
|
/// Raised when there is general error when deserializing a type.
|
||||||
///
|
///
|
||||||
/// The message should not be capitalized and should not end with a period.
|
/// The message should not be capitalized and should not end with a period.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// #
|
/// #
|
||||||
/// # struct IpAddr;
|
/// # struct IpAddr;
|
||||||
@@ -205,7 +210,7 @@ macro_rules! declare_error_trait {
|
|||||||
/// containing an integer, the unexpected type is the integer and the
|
/// containing an integer, the unexpected type is the integer and the
|
||||||
/// expected type is the string.
|
/// expected type is the string.
|
||||||
#[cold]
|
#[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))
|
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +228,7 @@ macro_rules! declare_error_trait {
|
|||||||
/// that is not valid UTF-8, the unexpected value is the bytes and the
|
/// that is not valid UTF-8, the unexpected value is the bytes and the
|
||||||
/// expected value is a string.
|
/// expected value is a string.
|
||||||
#[cold]
|
#[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))
|
Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ macro_rules! declare_error_trait {
|
|||||||
/// expected. For example `exp` might say that a tuple of size 6 was
|
/// expected. For example `exp` might say that a tuple of size 6 was
|
||||||
/// expected.
|
/// expected.
|
||||||
#[cold]
|
#[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))
|
Error::custom(format_args!("invalid length {}, expected {}", len, exp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +312,7 @@ declare_error_trait!(Error: Sized + Debug + Display);
|
|||||||
/// This is used as an argument to the `invalid_type`, `invalid_value`, and
|
/// This is used as an argument to the `invalid_type`, `invalid_value`, and
|
||||||
/// `invalid_length` methods of the `Error` trait to build error messages.
|
/// `invalid_length` methods of the `Error` trait to build error messages.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # use serde::de::{self, Unexpected, Visitor};
|
/// # use serde::de::{self, Unexpected, Visitor};
|
||||||
@@ -400,20 +405,20 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
|||||||
Bool(b) => write!(formatter, "boolean `{}`", b),
|
Bool(b) => write!(formatter, "boolean `{}`", b),
|
||||||
Unsigned(i) => write!(formatter, "integer `{}`", i),
|
Unsigned(i) => write!(formatter, "integer `{}`", i),
|
||||||
Signed(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),
|
Char(c) => write!(formatter, "character `{}`", c),
|
||||||
Str(s) => write!(formatter, "string {:?}", s),
|
Str(s) => write!(formatter, "string {:?}", s),
|
||||||
Bytes(_) => write!(formatter, "byte array"),
|
Bytes(_) => formatter.write_str("byte array"),
|
||||||
Unit => write!(formatter, "unit value"),
|
Unit => formatter.write_str("unit value"),
|
||||||
Option => write!(formatter, "Option value"),
|
Option => formatter.write_str("Option value"),
|
||||||
NewtypeStruct => write!(formatter, "newtype struct"),
|
NewtypeStruct => formatter.write_str("newtype struct"),
|
||||||
Seq => write!(formatter, "sequence"),
|
Seq => formatter.write_str("sequence"),
|
||||||
Map => write!(formatter, "map"),
|
Map => formatter.write_str("map"),
|
||||||
Enum => write!(formatter, "enum"),
|
Enum => formatter.write_str("enum"),
|
||||||
UnitVariant => write!(formatter, "unit variant"),
|
UnitVariant => formatter.write_str("unit variant"),
|
||||||
NewtypeVariant => write!(formatter, "newtype variant"),
|
NewtypeVariant => formatter.write_str("newtype variant"),
|
||||||
TupleVariant => write!(formatter, "tuple variant"),
|
TupleVariant => formatter.write_str("tuple variant"),
|
||||||
StructVariant => write!(formatter, "struct variant"),
|
StructVariant => formatter.write_str("struct variant"),
|
||||||
Other(other) => formatter.write_str(other),
|
Other(other) => formatter.write_str(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,10 +437,9 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
|||||||
/// Within the context of a `Visitor` implementation, the `Visitor` itself
|
/// Within the context of a `Visitor` implementation, the `Visitor` itself
|
||||||
/// (`&self`) is an implementation of this trait.
|
/// (`&self`) is an implementation of this trait.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
|
||||||
/// #
|
|
||||||
/// # use serde::de::{self, Unexpected, Visitor};
|
/// # use serde::de::{self, Unexpected, Visitor};
|
||||||
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # struct Example;
|
/// # struct Example;
|
||||||
/// #
|
/// #
|
||||||
@@ -457,7 +461,7 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
|||||||
///
|
///
|
||||||
/// Outside of a `Visitor`, `&"..."` can be used.
|
/// Outside of a `Visitor`, `&"..."` can be used.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, Unexpected};
|
/// # use serde::de::{self, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # fn example<E>() -> Result<(), E>
|
/// # fn example<E>() -> Result<(), E>
|
||||||
@@ -465,9 +469,18 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
|||||||
/// # E: de::Error,
|
/// # E: de::Error,
|
||||||
/// # {
|
/// # {
|
||||||
/// # let v = true;
|
/// # let v = true;
|
||||||
/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer"));
|
/// return Err(de::Error::invalid_type(
|
||||||
|
/// Unexpected::Bool(v),
|
||||||
|
/// &"a negative integer",
|
||||||
|
/// ));
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(
|
||||||
|
not(no_diagnostic_namespace),
|
||||||
|
diagnostic::on_unimplemented(
|
||||||
|
message = "the trait bound `{Self}: serde::de::Expected` is not satisfied",
|
||||||
|
)
|
||||||
|
)]
|
||||||
pub trait Expected {
|
pub trait Expected {
|
||||||
/// Format an explanation of what data was being expected. Same signature as
|
/// Format an explanation of what data was being expected. Same signature as
|
||||||
/// the `Display` and `Debug` traits.
|
/// the `Display` and `Debug` traits.
|
||||||
@@ -483,13 +496,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Expected for &'a str {
|
impl Expected for &str {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str(self)
|
formatter.write_str(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for Expected + 'a {
|
impl Display for dyn Expected + '_ {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
Expected::fmt(self, formatter)
|
Expected::fmt(self, formatter)
|
||||||
}
|
}
|
||||||
@@ -528,6 +541,16 @@ impl<'a> Display for Expected + 'a {
|
|||||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||||
///
|
///
|
||||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
/// [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 {
|
pub trait Deserialize<'de>: Sized {
|
||||||
/// Deserialize this value from the given Serde deserializer.
|
/// Deserialize this value from the given Serde deserializer.
|
||||||
///
|
///
|
||||||
@@ -564,7 +587,7 @@ pub trait Deserialize<'de>: Sized {
|
|||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
// Default implementation just delegates to `deserialize` impl.
|
// Default implementation just delegates to `deserialize` impl.
|
||||||
*place = try!(Deserialize::deserialize(deserializer));
|
*place = tri!(Deserialize::deserialize(deserializer));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -577,7 +600,7 @@ pub trait Deserialize<'de>: Sized {
|
|||||||
/// from the input string, but a `from_reader` function may only deserialize
|
/// from the input string, but a `from_reader` function may only deserialize
|
||||||
/// owned data.
|
/// owned data.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{Deserialize, DeserializeOwned};
|
/// # use serde::de::{Deserialize, DeserializeOwned};
|
||||||
/// # use std::io::{Read, Result};
|
/// # use std::io::{Read, Result};
|
||||||
/// #
|
/// #
|
||||||
@@ -600,6 +623,12 @@ pub trait Deserialize<'de>: Sized {
|
|||||||
/// lifetimes].
|
/// lifetimes].
|
||||||
///
|
///
|
||||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
/// [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> {}
|
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
|
||||||
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
||||||
|
|
||||||
@@ -616,7 +645,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
///
|
///
|
||||||
/// The canonical API for stateless deserialization looks like this:
|
/// The canonical API for stateless deserialization looks like this:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::Deserialize;
|
/// # use serde::Deserialize;
|
||||||
/// #
|
/// #
|
||||||
/// # enum Error {}
|
/// # enum Error {}
|
||||||
@@ -630,7 +659,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
/// Adjusting an API like this to support stateful deserialization is a matter
|
/// Adjusting an API like this to support stateful deserialization is a matter
|
||||||
/// of accepting a seed as input:
|
/// of accepting a seed as input:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::DeserializeSeed;
|
/// # use serde::de::DeserializeSeed;
|
||||||
/// #
|
/// #
|
||||||
/// # enum Error {}
|
/// # enum Error {}
|
||||||
@@ -663,12 +692,11 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
/// into it. This requires stateful deserialization using the `DeserializeSeed`
|
/// into it. This requires stateful deserialization using the `DeserializeSeed`
|
||||||
/// trait.
|
/// trait.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
|
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
|
||||||
/// use std::fmt;
|
/// use std::fmt;
|
||||||
/// use std::marker::PhantomData;
|
/// use std::marker::PhantomData;
|
||||||
///
|
///
|
||||||
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
|
|
||||||
///
|
|
||||||
/// // A DeserializeSeed implementation that uses stateful deserialization to
|
/// // A DeserializeSeed implementation that uses stateful deserialization to
|
||||||
/// // append array elements onto the end of an existing vector. The preexisting
|
/// // append array elements onto the end of an existing vector. The preexisting
|
||||||
/// // state ("seed") in this case is the Vec<T>. The `deserialize` method of
|
/// // state ("seed") in this case is the Vec<T>. The `deserialize` method of
|
||||||
@@ -709,7 +737,7 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
/// {
|
/// {
|
||||||
/// // Decrease the number of reallocations if there are many elements
|
/// // Decrease the number of reallocations if there are many elements
|
||||||
/// if let Some(size_hint) = seq.size_hint() {
|
/// if let Some(size_hint) = seq.size_hint() {
|
||||||
/// self.0.reserve(size_hint);
|
/// self.0.reserve(size_hint);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Visit each element in the inner array and push it onto
|
/// // Visit each element in the inner array and push it onto
|
||||||
@@ -766,6 +794,12 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
/// # Ok(())
|
/// # 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 {
|
pub trait DeserializeSeed<'de>: Sized {
|
||||||
/// The type produced by using this seed.
|
/// The type produced by using this seed.
|
||||||
type Value;
|
type Value;
|
||||||
@@ -902,6 +936,12 @@ where
|
|||||||
/// a basic JSON `Deserializer`.
|
/// a basic JSON `Deserializer`.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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 {
|
pub trait Deserializer<'de>: Sized {
|
||||||
/// The error type that can be returned if some error occurs during
|
/// The error type that can be returned if some error occurs during
|
||||||
/// deserialization.
|
/// deserialization.
|
||||||
@@ -945,18 +985,15 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
where
|
where
|
||||||
V: Visitor<'de>;
|
V: Visitor<'de>;
|
||||||
|
|
||||||
serde_if_integer128! {
|
/// Hint that the `Deserialize` type is expecting an `i128` value.
|
||||||
/// Hint that the `Deserialize` type is expecting an `i128` value.
|
///
|
||||||
///
|
/// The default behavior unconditionally returns an error.
|
||||||
/// This method is available only on Rust compiler versions >=1.26. The
|
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
/// default behavior unconditionally returns an error.
|
where
|
||||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
V: Visitor<'de>,
|
||||||
where
|
{
|
||||||
V: Visitor<'de>
|
let _ = visitor;
|
||||||
{
|
Err(Error::custom("i128 is not supported"))
|
||||||
let _ = visitor;
|
|
||||||
Err(Error::custom("i128 is not supported"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hint that the `Deserialize` type is expecting a `u8` value.
|
/// Hint that the `Deserialize` type is expecting a `u8` value.
|
||||||
@@ -979,18 +1016,15 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
where
|
where
|
||||||
V: Visitor<'de>;
|
V: Visitor<'de>;
|
||||||
|
|
||||||
serde_if_integer128! {
|
/// Hint that the `Deserialize` type is expecting an `u128` value.
|
||||||
/// Hint that the `Deserialize` type is expecting an `u128` value.
|
///
|
||||||
///
|
/// The default behavior unconditionally returns an error.
|
||||||
/// This method is available only on Rust compiler versions >=1.26. The
|
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
/// default behavior unconditionally returns an error.
|
where
|
||||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
V: Visitor<'de>,
|
||||||
where
|
{
|
||||||
V: Visitor<'de>
|
let _ = visitor;
|
||||||
{
|
Err(Error::custom("u128 is not supported"))
|
||||||
let _ = visitor;
|
|
||||||
Err(Error::custom("u128 is not supported"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hint that the `Deserialize` type is expecting a `f32` value.
|
/// Hint that the `Deserialize` type is expecting a `f32` value.
|
||||||
@@ -1158,7 +1192,7 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
/// human-readable one and binary formats like Postcard will prefer the
|
/// human-readable one and binary formats like Postcard will prefer the
|
||||||
/// compact one.
|
/// compact one.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::ops::Add;
|
/// # use std::ops::Add;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// #
|
/// #
|
||||||
@@ -1223,13 +1257,9 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
// Not public API.
|
// Not public API.
|
||||||
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn __deserialize_content<V>(
|
fn __deserialize_content_v1<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
self,
|
|
||||||
_: ::actually_private::T,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<::private::de::Content<'de>, Self::Error>
|
|
||||||
where
|
where
|
||||||
V: Visitor<'de, Value = ::private::de::Content<'de>>,
|
V: Visitor<'de, Value = crate::private::Content<'de>>,
|
||||||
{
|
{
|
||||||
self.deserialize_any(visitor)
|
self.deserialize_any(visitor)
|
||||||
}
|
}
|
||||||
@@ -1249,10 +1279,9 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
|
||||||
/// #
|
|
||||||
/// # use serde::de::{self, Unexpected, Visitor};
|
/// # use serde::de::{self, Unexpected, Visitor};
|
||||||
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// /// A visitor that deserializes a long string - a string containing at least
|
/// /// A visitor that deserializes a long string - a string containing at least
|
||||||
/// /// some minimum number of bytes.
|
/// /// some minimum number of bytes.
|
||||||
@@ -1279,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 {
|
pub trait Visitor<'de>: Sized {
|
||||||
/// The value produced by this visitor.
|
/// The value produced by this visitor.
|
||||||
type Value;
|
type Value;
|
||||||
@@ -1290,7 +1325,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
/// "an integer between 0 and 64". The message should not be capitalized and
|
/// "an integer between 0 and 64". The message should not be capitalized and
|
||||||
/// should not end with a period.
|
/// should not end with a period.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # struct S {
|
/// # struct S {
|
||||||
@@ -1363,20 +1398,20 @@ pub trait Visitor<'de>: Sized {
|
|||||||
Err(Error::invalid_type(Unexpected::Signed(v), &self))
|
Err(Error::invalid_type(Unexpected::Signed(v), &self))
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_if_integer128! {
|
/// The input contains a `i128`.
|
||||||
/// The input contains a `i128`.
|
///
|
||||||
///
|
/// The default implementation fails with a type error.
|
||||||
/// This method is available only on Rust compiler versions >=1.26. The
|
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
||||||
/// default implementation fails with a type error.
|
where
|
||||||
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
E: Error,
|
||||||
where
|
{
|
||||||
E: Error,
|
let mut buf = [0u8; 58];
|
||||||
{
|
let mut writer = crate::format::Buf::new(&mut buf);
|
||||||
let mut buf = [0u8; 58];
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
||||||
let mut writer = format::Buf::new(&mut buf);
|
Err(Error::invalid_type(
|
||||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
Unexpected::Other(writer.as_str()),
|
||||||
Err(Error::invalid_type(Unexpected::Other(writer.as_str()), &self))
|
&self,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains a `u8`.
|
/// The input contains a `u8`.
|
||||||
@@ -1425,20 +1460,20 @@ pub trait Visitor<'de>: Sized {
|
|||||||
Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
|
Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_if_integer128! {
|
/// The input contains a `u128`.
|
||||||
/// The input contains a `u128`.
|
///
|
||||||
///
|
/// The default implementation fails with a type error.
|
||||||
/// This method is available only on Rust compiler versions >=1.26. The
|
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
||||||
/// default implementation fails with a type error.
|
where
|
||||||
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
E: Error,
|
||||||
where
|
{
|
||||||
E: Error,
|
let mut buf = [0u8; 57];
|
||||||
{
|
let mut writer = crate::format::Buf::new(&mut buf);
|
||||||
let mut buf = [0u8; 57];
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
||||||
let mut writer = format::Buf::new(&mut buf);
|
Err(Error::invalid_type(
|
||||||
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
Unexpected::Other(writer.as_str()),
|
||||||
Err(Error::invalid_type(Unexpected::Other(writer.as_str()), &self))
|
&self,
|
||||||
}
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains an `f32`.
|
/// The input contains an `f32`.
|
||||||
@@ -1474,7 +1509,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
self.visit_str(utf8::encode(v).as_str())
|
self.visit_str(v.encode_utf8(&mut [0u8; 4]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains a string. The lifetime of the string is ephemeral and
|
/// The input contains a string. The lifetime of the string is ephemeral and
|
||||||
@@ -1529,6 +1564,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
/// `String`.
|
/// `String`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
@@ -1551,7 +1587,6 @@ pub trait Visitor<'de>: Sized {
|
|||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
let _ = v;
|
|
||||||
Err(Error::invalid_type(Unexpected::Bytes(v), &self))
|
Err(Error::invalid_type(Unexpected::Bytes(v), &self))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1588,6 +1623,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
/// The default implementation forwards to `visit_bytes` and then drops the
|
/// The default implementation forwards to `visit_bytes` and then drops the
|
||||||
/// `Vec<u8>`.
|
/// `Vec<u8>`.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
@@ -1704,6 +1740,12 @@ pub trait Visitor<'de>: Sized {
|
|||||||
/// implementation of `SeqAccess` for a basic JSON data format.
|
/// implementation of `SeqAccess` for a basic JSON data format.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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> {
|
pub trait SeqAccess<'de> {
|
||||||
/// The error type that can be returned if some error occurs during
|
/// The error type that can be returned if some error occurs during
|
||||||
/// deserialization.
|
/// deserialization.
|
||||||
@@ -1738,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
|
where
|
||||||
A: SeqAccess<'de>,
|
A: ?Sized + SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
type Error = A::Error;
|
type Error = A::Error;
|
||||||
|
|
||||||
@@ -1786,6 +1828,12 @@ where
|
|||||||
/// implementation of `MapAccess` for a basic JSON data format.
|
/// implementation of `MapAccess` for a basic JSON data format.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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> {
|
pub trait MapAccess<'de> {
|
||||||
/// The error type that can be returned if some error occurs during
|
/// The error type that can be returned if some error occurs during
|
||||||
/// deserialization.
|
/// deserialization.
|
||||||
@@ -1831,9 +1879,9 @@ pub trait MapAccess<'de> {
|
|||||||
K: DeserializeSeed<'de>,
|
K: DeserializeSeed<'de>,
|
||||||
V: DeserializeSeed<'de>,
|
V: DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
match try!(self.next_key_seed(kseed)) {
|
match tri!(self.next_key_seed(kseed)) {
|
||||||
Some(key) => {
|
Some(key) => {
|
||||||
let value = try!(self.next_value_seed(vseed));
|
let value = tri!(self.next_value_seed(vseed));
|
||||||
Ok(Some((key, value)))
|
Ok(Some((key, value)))
|
||||||
}
|
}
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
@@ -1891,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
|
where
|
||||||
A: MapAccess<'de>,
|
A: ?Sized + MapAccess<'de>,
|
||||||
{
|
{
|
||||||
type Error = A::Error;
|
type Error = A::Error;
|
||||||
|
|
||||||
@@ -1978,6 +2026,12 @@ where
|
|||||||
/// implementation of `EnumAccess` for a basic JSON data format.
|
/// implementation of `EnumAccess` for a basic JSON data format.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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 {
|
pub trait EnumAccess<'de>: Sized {
|
||||||
/// The error type that can be returned if some error occurs during
|
/// The error type that can be returned if some error occurs during
|
||||||
/// deserialization.
|
/// deserialization.
|
||||||
@@ -2025,6 +2079,12 @@ pub trait EnumAccess<'de>: Sized {
|
|||||||
/// implementation of `VariantAccess` for a basic JSON data format.
|
/// implementation of `VariantAccess` for a basic JSON data format.
|
||||||
///
|
///
|
||||||
/// [example data format]: https://serde.rs/data-format.html
|
/// [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 {
|
pub trait VariantAccess<'de>: Sized {
|
||||||
/// The error type that can be returned if some error occurs during
|
/// The error type that can be returned if some error occurs during
|
||||||
/// deserialization. Must match the error type of our `EnumAccess`.
|
/// deserialization. Must match the error type of our `EnumAccess`.
|
||||||
@@ -2035,7 +2095,7 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// If the data contains a different type of variant, the following
|
/// If the data contains a different type of variant, the following
|
||||||
/// `invalid_type` error should be constructed:
|
/// `invalid_type` error should be constructed:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2075,7 +2135,7 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// If the data contains a different type of variant, the following
|
/// If the data contains a different type of variant, the following
|
||||||
/// `invalid_type` error should be constructed:
|
/// `invalid_type` error should be constructed:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2131,7 +2191,7 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// If the data contains a different type of variant, the following
|
/// If the data contains a different type of variant, the following
|
||||||
/// `invalid_type` error should be constructed:
|
/// `invalid_type` error should be constructed:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2148,11 +2208,7 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// # T: DeserializeSeed<'de>,
|
/// # T: DeserializeSeed<'de>,
|
||||||
/// # { unimplemented!() }
|
/// # { unimplemented!() }
|
||||||
/// #
|
/// #
|
||||||
/// fn tuple_variant<V>(
|
/// fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
|
||||||
/// self,
|
|
||||||
/// _len: usize,
|
|
||||||
/// _visitor: V,
|
|
||||||
/// ) -> Result<V::Value, Self::Error>
|
|
||||||
/// where
|
/// where
|
||||||
/// V: Visitor<'de>,
|
/// V: Visitor<'de>,
|
||||||
/// {
|
/// {
|
||||||
@@ -2178,7 +2234,7 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// If the data contains a different type of variant, the following
|
/// If the data contains a different type of variant, the following
|
||||||
/// `invalid_type` error should be constructed:
|
/// `invalid_type` error should be constructed:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2238,10 +2294,10 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
|
/// use serde::de::{value, Deserialize, IntoDeserializer};
|
||||||
|
/// use serde_derive::Deserialize;
|
||||||
/// use std::str::FromStr;
|
/// use std::str::FromStr;
|
||||||
/// use serde::Deserialize;
|
|
||||||
/// use serde::de::{value, IntoDeserializer};
|
|
||||||
///
|
///
|
||||||
/// #[derive(Deserialize)]
|
/// #[derive(Deserialize)]
|
||||||
/// enum Setting {
|
/// enum Setting {
|
||||||
@@ -2285,15 +2341,52 @@ impl Display for OneOf {
|
|||||||
1 => write!(formatter, "`{}`", self.names[0]),
|
1 => write!(formatter, "`{}`", self.names[0]),
|
||||||
2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]),
|
2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]),
|
||||||
_ => {
|
_ => {
|
||||||
try!(write!(formatter, "one of "));
|
tri!(formatter.write_str("one of "));
|
||||||
for (i, alt) in self.names.iter().enumerate() {
|
for (i, alt) in self.names.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
try!(write!(formatter, ", "));
|
tri!(formatter.write_str(", "));
|
||||||
}
|
}
|
||||||
try!(write!(formatter, "`{}`", alt));
|
tri!(write!(formatter, "`{}`", alt));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
//! Building blocks for deserializing basic values using the `IntoDeserializer`
|
//! Building blocks for deserializing basic values using the `IntoDeserializer`
|
||||||
//! trait.
|
//! trait.
|
||||||
//!
|
//!
|
||||||
//! ```edition2018
|
//! ```edition2021
|
||||||
|
//! use serde::de::{value, Deserialize, IntoDeserializer};
|
||||||
|
//! use serde_derive::Deserialize;
|
||||||
//! use std::str::FromStr;
|
//! use std::str::FromStr;
|
||||||
//! use serde::Deserialize;
|
|
||||||
//! use serde::de::{value, IntoDeserializer};
|
|
||||||
//!
|
//!
|
||||||
//! #[derive(Deserialize)]
|
//! #[derive(Deserialize)]
|
||||||
//! enum Setting {
|
//! enum Setting {
|
||||||
@@ -21,12 +21,12 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use self::private::{First, Second};
|
use self::private::{First, Second};
|
||||||
use __private::size_hint;
|
use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||||
use de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
use crate::private::size_hint;
|
||||||
use ser;
|
use crate::ser;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -113,6 +113,7 @@ impl Debug for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
&self.err
|
&self.err
|
||||||
@@ -175,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> {
|
impl<E> Debug for UnitDeserializer<E> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.debug_struct("UnitDeserializer").finish()
|
formatter.debug_struct("UnitDeserializer").finish()
|
||||||
@@ -185,12 +197,14 @@ impl<E> Debug for UnitDeserializer<E> {
|
|||||||
|
|
||||||
/// A deserializer that cannot be instantiated.
|
/// A deserializer that cannot be instantiated.
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||||
pub struct NeverDeserializer<E> {
|
pub struct NeverDeserializer<E> {
|
||||||
never: !,
|
never: !,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||||
impl<'de, E> IntoDeserializer<'de, E> for !
|
impl<'de, E> IntoDeserializer<'de, E> for !
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -223,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 {
|
macro_rules! primitive_deserializer {
|
||||||
@@ -277,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> {
|
impl<E> Debug for $name<E> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter
|
formatter
|
||||||
@@ -293,20 +330,17 @@ primitive_deserializer!(i8, "an `i8`.", I8Deserializer, visit_i8);
|
|||||||
primitive_deserializer!(i16, "an `i16`.", I16Deserializer, visit_i16);
|
primitive_deserializer!(i16, "an `i16`.", I16Deserializer, visit_i16);
|
||||||
primitive_deserializer!(i32, "an `i32`.", I32Deserializer, visit_i32);
|
primitive_deserializer!(i32, "an `i32`.", I32Deserializer, visit_i32);
|
||||||
primitive_deserializer!(i64, "an `i64`.", I64Deserializer, visit_i64);
|
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!(isize, "an `isize`.", IsizeDeserializer, visit_i64 as i64);
|
||||||
primitive_deserializer!(u8, "a `u8`.", U8Deserializer, visit_u8);
|
primitive_deserializer!(u8, "a `u8`.", U8Deserializer, visit_u8);
|
||||||
primitive_deserializer!(u16, "a `u16`.", U16Deserializer, visit_u16);
|
primitive_deserializer!(u16, "a `u16`.", U16Deserializer, visit_u16);
|
||||||
primitive_deserializer!(u64, "a `u64`.", U64Deserializer, visit_u64);
|
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!(usize, "a `usize`.", UsizeDeserializer, visit_u64 as u64);
|
||||||
primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32);
|
primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32);
|
||||||
primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64);
|
primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64);
|
||||||
primitive_deserializer!(char, "a `char`.", CharDeserializer, visit_char);
|
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`.
|
/// A deserializer holding a `u32`.
|
||||||
pub struct U32Deserializer<E> {
|
pub struct U32Deserializer<E> {
|
||||||
value: u32,
|
value: u32,
|
||||||
@@ -370,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>
|
impl<'de, E> de::EnumAccess<'de> for U32Deserializer<E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -459,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>
|
impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -538,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>
|
impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -566,6 +633,7 @@ impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
|
|||||||
|
|
||||||
/// A deserializer holding a `String`.
|
/// A deserializer holding a `String`.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
pub struct StringDeserializer<E> {
|
pub struct StringDeserializer<E> {
|
||||||
value: String,
|
value: String,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -582,6 +650,7 @@ impl<E> Clone for StringDeserializer<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
impl<'de, E> IntoDeserializer<'de, E> for String
|
impl<'de, E> IntoDeserializer<'de, E> for String
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -639,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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'de, E> de::EnumAccess<'de> for StringDeserializer<E>
|
impl<'de, E> de::EnumAccess<'de> for StringDeserializer<E>
|
||||||
where
|
where
|
||||||
@@ -669,6 +750,7 @@ impl<E> Debug for StringDeserializer<E> {
|
|||||||
|
|
||||||
/// A deserializer holding a `Cow<str>`.
|
/// A deserializer holding a `Cow<str>`.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
pub struct CowStrDeserializer<'a, E> {
|
pub struct CowStrDeserializer<'a, E> {
|
||||||
value: Cow<'a, str>,
|
value: Cow<'a, str>,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -685,6 +767,7 @@ impl<'a, E> Clone for CowStrDeserializer<'a, E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -745,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"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
|
impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E>
|
||||||
where
|
where
|
||||||
@@ -822,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> {
|
impl<'a, E> Debug for BytesDeserializer<'a, E> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter
|
formatter
|
||||||
@@ -870,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> {
|
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter
|
formatter
|
||||||
@@ -937,8 +1054,8 @@ where
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let v = try!(visitor.visit_seq(&mut self));
|
let v = tri!(visitor.visit_seq(&mut self));
|
||||||
try!(self.end());
|
tri!(self.end());
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,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>
|
impl<'de, I, T, E> de::SeqAccess<'de> for SeqDeserializer<I, E>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = T>,
|
I: Iterator<Item = T>,
|
||||||
@@ -980,7 +1110,7 @@ struct ExpectedInSeq(usize);
|
|||||||
impl Expected for ExpectedInSeq {
|
impl Expected for ExpectedInSeq {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.0 == 1 {
|
if self.0 == 1 {
|
||||||
write!(formatter, "1 element in sequence")
|
formatter.write_str("1 element in sequence")
|
||||||
} else {
|
} else {
|
||||||
write!(formatter, "{} elements in sequence", self.0)
|
write!(formatter, "{} elements in sequence", self.0)
|
||||||
}
|
}
|
||||||
@@ -1003,6 +1133,7 @@ where
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T>
|
||||||
where
|
where
|
||||||
T: IntoDeserializer<'de, E>,
|
T: IntoDeserializer<'de, E>,
|
||||||
@@ -1016,6 +1147,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T>
|
||||||
where
|
where
|
||||||
T: IntoDeserializer<'de, E> + Eq + Ord,
|
T: IntoDeserializer<'de, E> + Eq + Ord,
|
||||||
@@ -1029,6 +1161,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
|
impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S>
|
||||||
where
|
where
|
||||||
T: IntoDeserializer<'de, E> + Eq + Hash,
|
T: IntoDeserializer<'de, E> + Eq + Hash,
|
||||||
@@ -1077,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.
|
/// A deserializer that iterates over a map.
|
||||||
@@ -1162,8 +1306,8 @@ where
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = try!(visitor.visit_map(&mut self));
|
let value = tri!(visitor.visit_map(&mut self));
|
||||||
try!(self.end());
|
tri!(self.end());
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,8 +1315,8 @@ where
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let value = try!(visitor.visit_seq(&mut self));
|
let value = tri!(visitor.visit_seq(&mut self));
|
||||||
try!(self.end());
|
tri!(self.end());
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,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>
|
impl<'de, I, E> de::MapAccess<'de> for MapDeserializer<'de, I, E>
|
||||||
where
|
where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
@@ -1236,8 +1395,8 @@ where
|
|||||||
{
|
{
|
||||||
match self.next_pair() {
|
match self.next_pair() {
|
||||||
Some((key, value)) => {
|
Some((key, value)) => {
|
||||||
let key = try!(kseed.deserialize(key.into_deserializer()));
|
let key = tri!(kseed.deserialize(key.into_deserializer()));
|
||||||
let value = try!(vseed.deserialize(value.into_deserializer()));
|
let value = tri!(vseed.deserialize(value.into_deserializer()));
|
||||||
Ok(Some((key, value)))
|
Ok(Some((key, value)))
|
||||||
}
|
}
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
@@ -1341,7 +1500,7 @@ where
|
|||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
let mut pair_visitor = PairVisitor(Some(self.0), Some(self.1), PhantomData);
|
let mut pair_visitor = PairVisitor(Some(self.0), Some(self.1), PhantomData);
|
||||||
let pair = try!(visitor.visit_seq(&mut pair_visitor));
|
let pair = tri!(visitor.visit_seq(&mut pair_visitor));
|
||||||
if pair_visitor.1.is_none() {
|
if pair_visitor.1.is_none() {
|
||||||
Ok(pair)
|
Ok(pair)
|
||||||
} else {
|
} else {
|
||||||
@@ -1405,7 +1564,7 @@ struct ExpectedInMap(usize);
|
|||||||
impl Expected for ExpectedInMap {
|
impl Expected for ExpectedInMap {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.0 == 1 {
|
if self.0 == 1 {
|
||||||
write!(formatter, "1 element in map")
|
formatter.write_str("1 element in map")
|
||||||
} else {
|
} else {
|
||||||
write!(formatter, "{} elements in map", self.0)
|
write!(formatter, "{} elements in map", self.0)
|
||||||
}
|
}
|
||||||
@@ -1415,6 +1574,7 @@ impl Expected for ExpectedInMap {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[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>
|
impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V>
|
||||||
where
|
where
|
||||||
K: IntoDeserializer<'de, E> + Eq + Ord,
|
K: IntoDeserializer<'de, E> + Eq + Ord,
|
||||||
@@ -1429,6 +1589,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
|
impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S>
|
||||||
where
|
where
|
||||||
K: IntoDeserializer<'de, E> + Eq + Hash,
|
K: IntoDeserializer<'de, E> + Eq + Hash,
|
||||||
@@ -1490,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>
|
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
|
||||||
where
|
where
|
||||||
A: de::MapAccess<'de>,
|
A: de::MapAccess<'de>,
|
||||||
@@ -1501,7 +1673,7 @@ where
|
|||||||
where
|
where
|
||||||
T: de::DeserializeSeed<'de>,
|
T: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
match try!(self.map.next_key_seed(seed)) {
|
match tri!(self.map.next_key_seed(seed)) {
|
||||||
Some(key) => Ok((key, private::map_as_enum(self.map))),
|
Some(key) => Ok((key, private::map_as_enum(self.map))),
|
||||||
None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")),
|
None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")),
|
||||||
}
|
}
|
||||||
@@ -1543,12 +1715,25 @@ 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 {
|
mod private {
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor};
|
use crate::de::{
|
||||||
|
self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct UnitOnly<E> {
|
pub struct UnitOnly<E> {
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use lib::fmt::{self, Write};
|
use crate::lib::fmt::{self, Write};
|
||||||
use lib::str;
|
use crate::lib::str;
|
||||||
|
|
||||||
pub(super) struct Buf<'a> {
|
pub(super) struct Buf<'a> {
|
||||||
bytes: &'a mut [u8],
|
bytes: &'a mut [u8],
|
||||||
@@ -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.228")]
|
||||||
|
// 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
|
// Super explicit first paragraph because this shows up at the top level and
|
||||||
// trips up people who are just looking for basic Serialize / Deserialize
|
// trips up people who are just looking for basic Serialize / Deserialize
|
||||||
// documentation.
|
// documentation.
|
||||||
//
|
|
||||||
/// Helper macro when implementing the `Deserializer` part of a new data format
|
/// Helper macro when implementing the `Deserializer` part of a new data format
|
||||||
/// for Serde.
|
/// for Serde.
|
||||||
///
|
///
|
||||||
@@ -11,7 +10,7 @@
|
|||||||
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
||||||
/// trait methods.
|
/// trait methods.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::forward_to_deserialize_any;
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # use serde::de::{value, Deserializer, Visitor};
|
/// # use serde::de::{value, Deserializer, Visitor};
|
||||||
/// #
|
/// #
|
||||||
@@ -47,7 +46,7 @@
|
|||||||
/// methods so that they forward directly to [`Deserializer::deserialize_any`].
|
/// methods so that they forward directly to [`Deserializer::deserialize_any`].
|
||||||
/// You can choose which methods to forward.
|
/// You can choose which methods to forward.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::forward_to_deserialize_any;
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # use serde::de::{value, Deserializer, Visitor};
|
/// # use serde::de::{value, Deserializer, Visitor};
|
||||||
/// #
|
/// #
|
||||||
@@ -78,11 +77,10 @@
|
|||||||
/// called `V`. A different type parameter and a different lifetime can be
|
/// called `V`. A different type parameter and a different lifetime can be
|
||||||
/// specified explicitly if necessary.
|
/// specified explicitly if necessary.
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use std::marker::PhantomData;
|
|
||||||
/// #
|
|
||||||
/// # use serde::forward_to_deserialize_any;
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # use serde::de::{value, Deserializer, Visitor};
|
/// # use serde::de::{value, Deserializer, Visitor};
|
||||||
|
/// # use std::marker::PhantomData;
|
||||||
/// #
|
/// #
|
||||||
/// # struct MyDeserializer<V>(PhantomData<V>);
|
/// # struct MyDeserializer<V>(PhantomData<V>);
|
||||||
/// #
|
/// #
|
||||||
@@ -105,9 +103,9 @@
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Deserializer`]: trait.Deserializer.html
|
/// [`Deserializer`]: crate::Deserializer
|
||||||
/// [`Visitor`]: de/trait.Visitor.html
|
/// [`Visitor`]: crate::de::Visitor
|
||||||
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
|
/// [`Deserializer::deserialize_any`]: crate::Deserializer::deserialize_any
|
||||||
#[macro_export(local_inner_macros)]
|
#[macro_export(local_inner_macros)]
|
||||||
macro_rules! forward_to_deserialize_any {
|
macro_rules! forward_to_deserialize_any {
|
||||||
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
|
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
|
||||||
@@ -124,7 +122,7 @@ macro_rules! forward_to_deserialize_any {
|
|||||||
macro_rules! forward_to_deserialize_any_method {
|
macro_rules! forward_to_deserialize_any_method {
|
||||||
($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => {
|
($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => {
|
||||||
#[inline]
|
#[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
|
where
|
||||||
$v: $crate::de::Visitor<$l>,
|
$v: $crate::de::Visitor<$l>,
|
||||||
{
|
{
|
||||||
@@ -155,9 +153,7 @@ macro_rules! forward_to_deserialize_any_helper {
|
|||||||
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
|
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
|
||||||
};
|
};
|
||||||
(i128<$l:tt, $v:ident>) => {
|
(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>) => {
|
(u8<$l:tt, $v:ident>) => {
|
||||||
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
|
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
|
||||||
@@ -172,9 +168,7 @@ macro_rules! forward_to_deserialize_any_helper {
|
|||||||
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
|
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
|
||||||
};
|
};
|
||||||
(u128<$l:tt, $v:ident>) => {
|
(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>) => {
|
(f32<$l:tt, $v:ident>) => {
|
||||||
forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()}
|
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>)>),
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
// Used only by Serde doc tests. Not public API.
|
// Used only by Serde doc tests. Not public API.
|
||||||
|
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use ser;
|
use crate::ser;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Error;
|
pub struct Error;
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl ser::Error for Error {
|
impl ser::Error for Error {
|
||||||
fn custom<T>(_: T) -> Self
|
fn custom<T>(_: T) -> Self
|
||||||
where
|
where
|
||||||
@@ -18,12 +19,14 @@ impl ser::Error for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(no_diagnostic_namespace), diagnostic::do_not_recommend)]
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
@@ -56,7 +59,10 @@ macro_rules! __serialize_unimplemented {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! __serialize_unimplemented_method {
|
macro_rules! __serialize_unimplemented_method {
|
||||||
($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
|
($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!()
|
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;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
use de::{Deserialize, DeserializeSeed, Deserializer};
|
use crate::de::{Deserialize, DeserializeSeed, Deserializer};
|
||||||
|
|
||||||
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
|
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
|
||||||
///
|
///
|
||||||
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
||||||
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
|
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>
|
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>,
|
T: Deserialize<'de>,
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
use crate::lib::*;
|
||||||
|
|
||||||
|
pub fn from_bounds<I>(iter: &I) -> Option<usize>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
helper(iter.size_hint())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn cautious<Element>(hint: Option<usize>) -> usize {
|
||||||
|
const MAX_PREALLOC_BYTES: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
if mem::size_of::<Element>() == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
cmp::min(
|
||||||
|
hint.unwrap_or(0),
|
||||||
|
MAX_PREALLOC_BYTES / mem::size_of::<Element>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
|
||||||
|
match bounds {
|
||||||
|
(lower, Some(upper)) if lower == upper => Some(upper),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}")
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use lib::*;
|
use crate::lib::*;
|
||||||
use ser::{Error, Impossible, Serialize, Serializer};
|
use crate::ser::{Error, Impossible, Serialize, Serializer};
|
||||||
|
|
||||||
impl Error for fmt::Error {
|
impl Error for fmt::Error {
|
||||||
fn custom<T: Display>(_msg: T) -> Self {
|
fn custom<T: Display>(_msg: T) -> Self {
|
||||||
@@ -17,8 +17,9 @@ macro_rules! fmt_primitives {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// use serde::Serialize;
|
/// use serde::ser::Serialize;
|
||||||
|
/// use serde_derive::Serialize;
|
||||||
/// use std::fmt::{self, Display};
|
/// use std::fmt::{self, Display};
|
||||||
///
|
///
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Serialize)]
|
||||||
@@ -34,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 Ok = ();
|
||||||
type Error = fmt::Error;
|
type Error = fmt::Error;
|
||||||
type SerializeSeq = Impossible<(), fmt::Error>;
|
type SerializeSeq = Impossible<(), fmt::Error>;
|
||||||
@@ -51,10 +52,12 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
serialize_i16: i16,
|
serialize_i16: i16,
|
||||||
serialize_i32: i32,
|
serialize_i32: i32,
|
||||||
serialize_i64: i64,
|
serialize_i64: i64,
|
||||||
|
serialize_i128: i128,
|
||||||
serialize_u8: u8,
|
serialize_u8: u8,
|
||||||
serialize_u16: u16,
|
serialize_u16: u16,
|
||||||
serialize_u32: u32,
|
serialize_u32: u32,
|
||||||
serialize_u64: u64,
|
serialize_u64: u64,
|
||||||
|
serialize_u128: u128,
|
||||||
serialize_f32: f32,
|
serialize_f32: f32,
|
||||||
serialize_f64: f64,
|
serialize_f64: f64,
|
||||||
serialize_char: char,
|
serialize_char: char,
|
||||||
@@ -62,13 +65,6 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
serialize_unit_struct: &'static str,
|
serialize_unit_struct: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_if_integer128! {
|
|
||||||
fmt_primitives! {
|
|
||||||
serialize_i128: i128,
|
|
||||||
serialize_u128: u128,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
@@ -78,9 +74,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
Display::fmt(variant, self)
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Serialize::serialize(value, self)
|
Serialize::serialize(value, self)
|
||||||
}
|
}
|
||||||
@@ -93,9 +89,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
Err(fmt::Error)
|
Err(fmt::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> fmt::Result
|
fn serialize_some<T>(self, _value: &T) -> fmt::Result
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Err(fmt::Error)
|
Err(fmt::Error)
|
||||||
}
|
}
|
||||||
@@ -104,7 +100,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
Err(fmt::Error)
|
Err(fmt::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
fn serialize_newtype_variant<T>(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
@@ -112,7 +108,7 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
_value: &T,
|
_value: &T,
|
||||||
) -> fmt::Result
|
) -> fmt::Result
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
Err(fmt::Error)
|
Err(fmt::Error)
|
||||||
}
|
}
|
||||||
@@ -165,9 +161,9 @@ impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
|||||||
Err(fmt::Error)
|
Err(fmt::Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_str<T: ?Sized>(self, value: &T) -> fmt::Result
|
fn collect_str<T>(self, value: &T) -> fmt::Result
|
||||||
where
|
where
|
||||||
T: Display,
|
T: ?Sized + Display,
|
||||||
{
|
{
|
||||||
Display::fmt(value, self)
|
Display::fmt(value, self)
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use ser::{Error, Serialize, SerializeTuple, Serializer};
|
use crate::ser::{Error, Serialize, SerializeTuple, Serializer};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -24,20 +24,17 @@ primitive_impl!(i8, serialize_i8);
|
|||||||
primitive_impl!(i16, serialize_i16);
|
primitive_impl!(i16, serialize_i16);
|
||||||
primitive_impl!(i32, serialize_i32);
|
primitive_impl!(i32, serialize_i32);
|
||||||
primitive_impl!(i64, serialize_i64);
|
primitive_impl!(i64, serialize_i64);
|
||||||
|
primitive_impl!(i128, serialize_i128);
|
||||||
primitive_impl!(usize, serialize_u64 as u64);
|
primitive_impl!(usize, serialize_u64 as u64);
|
||||||
primitive_impl!(u8, serialize_u8);
|
primitive_impl!(u8, serialize_u8);
|
||||||
primitive_impl!(u16, serialize_u16);
|
primitive_impl!(u16, serialize_u16);
|
||||||
primitive_impl!(u32, serialize_u32);
|
primitive_impl!(u32, serialize_u32);
|
||||||
primitive_impl!(u64, serialize_u64);
|
primitive_impl!(u64, serialize_u64);
|
||||||
|
primitive_impl!(u128, serialize_u128);
|
||||||
primitive_impl!(f32, serialize_f32);
|
primitive_impl!(f32, serialize_f32);
|
||||||
primitive_impl!(f64, serialize_f64);
|
primitive_impl!(f64, serialize_f64);
|
||||||
primitive_impl!(char, serialize_char);
|
primitive_impl!(char, serialize_char);
|
||||||
|
|
||||||
serde_if_integer128! {
|
|
||||||
primitive_impl!(i128, serialize_i128);
|
|
||||||
primitive_impl!(u128, serialize_u128);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl Serialize for str {
|
impl Serialize for str {
|
||||||
@@ -51,6 +48,7 @@ impl Serialize for str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
impl Serialize for String {
|
impl Serialize for String {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
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(any(feature = "std", not(no_core_cstr)))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl Serialize for CStr {
|
impl Serialize for CStr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
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(any(feature = "std", all(not(no_core_cstr), feature = "alloc")))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
impl Serialize for CString {
|
impl Serialize for CString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
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]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -133,7 +136,7 @@ impl<T> Serialize for [T; 0] {
|
|||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
try!(serializer.serialize_tuple(0)).end()
|
tri!(serializer.serialize_tuple(0)).end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,9 +152,9 @@ macro_rules! array_impls {
|
|||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let mut seq = try!(serializer.serialize_tuple($len));
|
let mut seq = tri!(serializer.serialize_tuple($len));
|
||||||
for e in self {
|
for e in self {
|
||||||
try!(seq.serialize_element(e));
|
tri!(seq.serialize_element(e));
|
||||||
}
|
}
|
||||||
seq.end()
|
seq.end()
|
||||||
}
|
}
|
||||||
@@ -182,9 +185,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(any(feature = "std", feature = "alloc"), not(no_relaxed_trait_bounds)))]
|
|
||||||
macro_rules! seq_impl {
|
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)*>
|
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -200,42 +206,41 @@ macro_rules! seq_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(any(feature = "std", feature = "alloc"), no_relaxed_trait_bounds))]
|
seq_impl! {
|
||||||
macro_rules! seq_impl {
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
($ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>) => {
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
BinaryHeap<T>
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
seq_impl! {
|
||||||
seq_impl!(BinaryHeap<T: Ord>);
|
#[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! {
|
||||||
seq_impl!(BTreeSet<T: Ord>);
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
HashSet<T, H: BuildHasher>
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
seq_impl! {
|
||||||
seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>);
|
#[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! {
|
||||||
seq_impl!(LinkedList<T>);
|
#[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! {
|
||||||
seq_impl!(Vec<T>);
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
VecDeque<T>
|
||||||
seq_impl!(VecDeque<T>);
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -248,16 +253,32 @@ where
|
|||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
use super::SerializeStruct;
|
use super::SerializeStruct;
|
||||||
let mut state = try!(serializer.serialize_struct("Range", 2));
|
let mut state = tri!(serializer.serialize_struct("Range", 2));
|
||||||
try!(state.serialize_field("start", &self.start));
|
tri!(state.serialize_field("start", &self.start));
|
||||||
try!(state.serialize_field("end", &self.end));
|
tri!(state.serialize_field("end", &self.end));
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<Idx> Serialize for RangeFrom<Idx>
|
||||||
|
where
|
||||||
|
Idx: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
use super::SerializeStruct;
|
||||||
|
let mut state = tri!(serializer.serialize_struct("RangeFrom", 1));
|
||||||
|
tri!(state.serialize_field("start", &self.start));
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(not(no_range_inclusive))]
|
|
||||||
impl<Idx> Serialize for RangeInclusive<Idx>
|
impl<Idx> Serialize for RangeInclusive<Idx>
|
||||||
where
|
where
|
||||||
Idx: Serialize,
|
Idx: Serialize,
|
||||||
@@ -267,16 +288,32 @@ where
|
|||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
use super::SerializeStruct;
|
use super::SerializeStruct;
|
||||||
let mut state = try!(serializer.serialize_struct("RangeInclusive", 2));
|
let mut state = tri!(serializer.serialize_struct("RangeInclusive", 2));
|
||||||
try!(state.serialize_field("start", &self.start()));
|
tri!(state.serialize_field("start", &self.start()));
|
||||||
try!(state.serialize_field("end", &self.end()));
|
tri!(state.serialize_field("end", &self.end()));
|
||||||
|
state.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<Idx> Serialize for RangeTo<Idx>
|
||||||
|
where
|
||||||
|
Idx: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
use super::SerializeStruct;
|
||||||
|
let mut state = tri!(serializer.serialize_struct("RangeTo", 1));
|
||||||
|
tri!(state.serialize_field("end", &self.end));
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(not(no_ops_bound), all(feature = "std", not(no_collections_bound))))]
|
|
||||||
impl<T> Serialize for Bound<T>
|
impl<T> Serialize for Bound<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -310,6 +347,7 @@ impl Serialize for () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
|
||||||
impl Serialize for ! {
|
impl Serialize for ! {
|
||||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -324,28 +362,46 @@ impl Serialize for ! {
|
|||||||
macro_rules! tuple_impls {
|
macro_rules! tuple_impls {
|
||||||
($($len:expr => ($($n:tt $name:ident)+))+) => {
|
($($len:expr => ($($n:tt $name:ident)+))+) => {
|
||||||
$(
|
$(
|
||||||
|
#[cfg_attr(docsrs, doc(hidden))]
|
||||||
impl<$($name),+> Serialize for ($($name,)+)
|
impl<$($name),+> Serialize for ($($name,)+)
|
||||||
where
|
where
|
||||||
$($name: Serialize,)+
|
$($name: Serialize,)+
|
||||||
{
|
{
|
||||||
#[inline]
|
tuple_impl_body!($len => ($($n)+));
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let mut tuple = try!(serializer.serialize_tuple($len));
|
|
||||||
$(
|
|
||||||
try!(tuple.serialize_element(&self.$n));
|
|
||||||
)+
|
|
||||||
tuple.end()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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! {
|
tuple_impls! {
|
||||||
1 => (0 T0)
|
|
||||||
2 => (0 T0 1 T1)
|
2 => (0 T0 1 T1)
|
||||||
3 => (0 T0 1 T1 2 T2)
|
3 => (0 T0 1 T1 2 T2)
|
||||||
4 => (0 T0 1 T1 2 T2 3 T3)
|
4 => (0 T0 1 T1 2 T2 3 T3)
|
||||||
@@ -365,9 +421,12 @@ tuple_impls! {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(all(any(feature = "std", feature = "alloc"), not(no_relaxed_trait_bounds)))]
|
|
||||||
macro_rules! map_impl {
|
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)*>
|
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
|
||||||
where
|
where
|
||||||
K: Serialize,
|
K: Serialize,
|
||||||
@@ -384,40 +443,26 @@ macro_rules! map_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(any(feature = "std", feature = "alloc"), no_relaxed_trait_bounds))]
|
map_impl! {
|
||||||
macro_rules! map_impl {
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
($ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)*>) => {
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*>
|
BTreeMap<K: Ord, V>
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
map_impl! {
|
||||||
map_impl!(BTreeMap<K: Ord, V>);
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
#[cfg(feature = "std")]
|
HashMap<K: Eq + Hash, V, H: BuildHasher>
|
||||||
map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! deref_impl {
|
macro_rules! deref_impl {
|
||||||
(
|
(
|
||||||
$(#[doc = $doc:tt])*
|
$(#[$attr:meta])*
|
||||||
<$($desc:tt)+
|
<$($desc:tt)+
|
||||||
) => {
|
) => {
|
||||||
$(#[doc = $doc])*
|
$(#[$attr])*
|
||||||
impl <$($desc)+ {
|
impl <$($desc)+ {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@@ -430,13 +475,20 @@ macro_rules! deref_impl {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
deref_impl!(<'a, T: ?Sized> Serialize for &'a T where T: Serialize);
|
deref_impl! {
|
||||||
deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize);
|
<'a, T> Serialize for &'a T where T: ?Sized + Serialize
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
deref_impl! {
|
||||||
deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize);
|
<'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! {
|
deref_impl! {
|
||||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||||
///
|
///
|
||||||
@@ -446,10 +498,11 @@ deref_impl! {
|
|||||||
/// repeated data.
|
/// repeated data.
|
||||||
///
|
///
|
||||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
/// [`"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! {
|
deref_impl! {
|
||||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||||
///
|
///
|
||||||
@@ -459,11 +512,16 @@ deref_impl! {
|
|||||||
/// repeated data.
|
/// repeated data.
|
||||||
///
|
///
|
||||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
/// [`"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! {
|
||||||
deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned);
|
#[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
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -471,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
|
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
#[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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -487,9 +549,13 @@ where
|
|||||||
///
|
///
|
||||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
#[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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -504,7 +570,6 @@ where
|
|||||||
macro_rules! nonzero_integers {
|
macro_rules! nonzero_integers {
|
||||||
($($T:ident,)+) => {
|
($($T:ident,)+) => {
|
||||||
$(
|
$(
|
||||||
#[cfg(not(no_num_nonzero))]
|
|
||||||
impl Serialize for num::$T {
|
impl Serialize for num::$T {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -517,34 +582,19 @@ macro_rules! nonzero_integers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonzero_integers! {
|
|
||||||
NonZeroU8,
|
|
||||||
NonZeroU16,
|
|
||||||
NonZeroU32,
|
|
||||||
NonZeroU64,
|
|
||||||
NonZeroUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(no_num_nonzero_signed))]
|
|
||||||
nonzero_integers! {
|
nonzero_integers! {
|
||||||
NonZeroI8,
|
NonZeroI8,
|
||||||
NonZeroI16,
|
NonZeroI16,
|
||||||
NonZeroI32,
|
NonZeroI32,
|
||||||
NonZeroI64,
|
NonZeroI64,
|
||||||
|
NonZeroI128,
|
||||||
NonZeroIsize,
|
NonZeroIsize,
|
||||||
}
|
NonZeroU8,
|
||||||
|
NonZeroU16,
|
||||||
// Currently 128-bit integers do not work on Emscripten targets so we need an
|
NonZeroU32,
|
||||||
// additional `#[cfg]`
|
NonZeroU64,
|
||||||
serde_if_integer128! {
|
NonZeroU128,
|
||||||
nonzero_integers! {
|
NonZeroUsize,
|
||||||
NonZeroU128,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(no_num_nonzero_signed))]
|
|
||||||
nonzero_integers! {
|
|
||||||
NonZeroI128,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Serialize for Cell<T>
|
impl<T> Serialize for Cell<T>
|
||||||
@@ -559,9 +609,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Serialize for RefCell<T>
|
impl<T> Serialize for RefCell<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -575,9 +625,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<T: ?Sized> Serialize for Mutex<T>
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
impl<T> Serialize for Mutex<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -591,9 +642,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<T: ?Sized> Serialize for RwLock<T>
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
impl<T> Serialize for RwLock<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -608,6 +660,8 @@ where
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(feature = "result")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "result")))]
|
||||||
impl<T, E> Serialize for Result<T, E>
|
impl<T, E> Serialize for Result<T, E>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -628,16 +682,15 @@ where
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(feature = "std", not(no_core_duration)))]
|
|
||||||
impl Serialize for Duration {
|
impl Serialize for Duration {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
use super::SerializeStruct;
|
use super::SerializeStruct;
|
||||||
let mut state = try!(serializer.serialize_struct("Duration", 2));
|
let mut state = tri!(serializer.serialize_struct("Duration", 2));
|
||||||
try!(state.serialize_field("secs", &self.as_secs()));
|
tri!(state.serialize_field("secs", &self.as_secs()));
|
||||||
try!(state.serialize_field("nanos", &self.subsec_nanos()));
|
tri!(state.serialize_field("nanos", &self.subsec_nanos()));
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,6 +698,7 @@ impl Serialize for Duration {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl Serialize for SystemTime {
|
impl Serialize for SystemTime {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -655,9 +709,9 @@ impl Serialize for SystemTime {
|
|||||||
Ok(duration_since_epoch) => duration_since_epoch,
|
Ok(duration_since_epoch) => duration_since_epoch,
|
||||||
Err(_) => return Err(S::Error::custom("SystemTime must be later than UNIX_EPOCH")),
|
Err(_) => return Err(S::Error::custom("SystemTime must be later than UNIX_EPOCH")),
|
||||||
};
|
};
|
||||||
let mut state = try!(serializer.serialize_struct("SystemTime", 2));
|
let mut state = tri!(serializer.serialize_struct("SystemTime", 2));
|
||||||
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
tri!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
||||||
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
tri!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,27 +722,17 @@ impl Serialize for SystemTime {
|
|||||||
/// statically known to never have more than a constant `MAX_LEN` bytes.
|
/// 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.
|
/// 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 {
|
macro_rules! serialize_display_bounded_length {
|
||||||
($value:expr, $max:expr, $serializer:expr) => {{
|
($value:expr, $max:expr, $serializer:expr) => {{
|
||||||
let mut buffer = [0u8; $max];
|
let mut buffer = [0u8; $max];
|
||||||
let remaining_len = {
|
let mut writer = crate::format::Buf::new(&mut buffer);
|
||||||
let mut remaining = &mut buffer[..];
|
write!(&mut writer, "{}", $value).unwrap();
|
||||||
write!(remaining, "{}", $value).unwrap();
|
$serializer.serialize_str(writer.as_str())
|
||||||
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)
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::IpAddr {
|
impl Serialize for net::IpAddr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -712,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"\
|
const DEC_DIGITS_LUT: &[u8] = b"\
|
||||||
0001020304050607080910111213141516171819\
|
0001020304050607080910111213141516171819\
|
||||||
2021222324252627282930313233343536373839\
|
2021222324252627282930313233343536373839\
|
||||||
@@ -720,7 +764,7 @@ const DEC_DIGITS_LUT: &[u8] = b"\
|
|||||||
6061626364656667686970717273747576777879\
|
6061626364656667686970717273747576777879\
|
||||||
8081828384858687888990919293949596979899";
|
8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
||||||
if n >= 100 {
|
if n >= 100 {
|
||||||
@@ -741,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]
|
#[test]
|
||||||
fn test_format_u8() {
|
fn test_format_u8() {
|
||||||
let mut i = 0u8;
|
let mut i = 0u8;
|
||||||
@@ -758,7 +802,7 @@ fn test_format_u8() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::Ipv4Addr {
|
impl Serialize for net::Ipv4Addr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -782,7 +826,7 @@ impl Serialize for net::Ipv4Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::Ipv6Addr {
|
impl Serialize for net::Ipv6Addr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -798,7 +842,7 @@ impl Serialize for net::Ipv6Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::SocketAddr {
|
impl Serialize for net::SocketAddr {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -822,7 +866,7 @@ impl Serialize for net::SocketAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::SocketAddrV4 {
|
impl Serialize for net::SocketAddrV4 {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -838,7 +882,7 @@ impl Serialize for net::SocketAddrV4 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(any(feature = "std", not(no_core_net)))]
|
||||||
impl Serialize for net::SocketAddrV6 {
|
impl Serialize for net::SocketAddrV6 {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -860,6 +904,7 @@ impl Serialize for net::SocketAddrV6 {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl Serialize for Path {
|
impl Serialize for Path {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -873,6 +918,7 @@ impl Serialize for Path {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl Serialize for PathBuf {
|
impl Serialize for PathBuf {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -883,6 +929,7 @@ impl Serialize for PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
|
||||||
impl Serialize for OsStr {
|
impl Serialize for OsStr {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@@ -905,6 +952,7 @@ impl Serialize for OsStr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "std", any(unix, windows)))]
|
#[cfg(all(feature = "std", any(unix, windows)))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", any(unix, windows)))))]
|
||||||
impl Serialize for OsString {
|
impl Serialize for OsString {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -929,7 +977,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(no_core_reverse))]
|
#[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>
|
impl<T> Serialize for Reverse<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -950,6 +1011,7 @@ macro_rules! atomic_impl {
|
|||||||
($($ty:ident $size:expr)*) => {
|
($($ty:ident $size:expr)*) => {
|
||||||
$(
|
$(
|
||||||
#[cfg(any(no_target_has_atomic, target_has_atomic = $size))]
|
#[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 {
|
impl Serialize for $ty {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
//! This module contains `Impossible` serializer and its implementations.
|
//! This module contains `Impossible` serializer and its implementations.
|
||||||
|
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use ser::{
|
use crate::ser::{
|
||||||
self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||||
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
|
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
|
||||||
};
|
};
|
||||||
@@ -15,9 +15,9 @@ use ser::{
|
|||||||
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
||||||
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// # use serde::ser::{Serializer, Impossible};
|
/// # use serde::ser::{Serializer, Impossible};
|
||||||
/// # use serde::__private::doc::Error;
|
/// # use serde_core::__private::doc::Error;
|
||||||
/// #
|
/// #
|
||||||
/// # struct MySerializer;
|
/// # struct MySerializer;
|
||||||
/// #
|
/// #
|
||||||
@@ -41,7 +41,7 @@ use ser::{
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /* other Serializer methods */
|
/// /* 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
|
/// # 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
|
/// # unit unit_struct unit_variant newtype_struct newtype_variant
|
||||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||||
@@ -49,14 +49,14 @@ use ser::{
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Serializer`]: trait.Serializer.html
|
/// [`Serializer`]: crate::Serializer
|
||||||
/// [`SerializeSeq`]: trait.SerializeSeq.html
|
/// [`SerializeSeq`]: crate::ser::SerializeSeq
|
||||||
/// [`SerializeTuple`]: trait.SerializeTuple.html
|
/// [`SerializeTuple`]: crate::ser::SerializeTuple
|
||||||
/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html
|
/// [`SerializeTupleStruct`]: crate::ser::SerializeTupleStruct
|
||||||
/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html
|
/// [`SerializeTupleVariant`]: crate::ser::SerializeTupleVariant
|
||||||
/// [`SerializeMap`]: trait.SerializeMap.html
|
/// [`SerializeMap`]: crate::ser::SerializeMap
|
||||||
/// [`SerializeStruct`]: trait.SerializeStruct.html
|
/// [`SerializeStruct`]: crate::ser::SerializeStruct
|
||||||
/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html
|
/// [`SerializeStructVariant`]: crate::ser::SerializeStructVariant
|
||||||
pub struct Impossible<Ok, Error> {
|
pub struct Impossible<Ok, Error> {
|
||||||
void: Void,
|
void: Void,
|
||||||
ok: PhantomData<Ok>,
|
ok: PhantomData<Ok>,
|
||||||
@@ -72,9 +72,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = value;
|
let _ = value;
|
||||||
match self.void {}
|
match self.void {}
|
||||||
@@ -92,9 +92,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = value;
|
let _ = value;
|
||||||
match self.void {}
|
match self.void {}
|
||||||
@@ -112,9 +112,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = value;
|
let _ = value;
|
||||||
match self.void {}
|
match self.void {}
|
||||||
@@ -132,9 +132,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = value;
|
let _ = value;
|
||||||
match self.void {}
|
match self.void {}
|
||||||
@@ -152,17 +152,17 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = key;
|
let _ = key;
|
||||||
match self.void {}
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = value;
|
let _ = value;
|
||||||
match self.void {}
|
match self.void {}
|
||||||
@@ -180,9 +180,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = key;
|
let _ = key;
|
||||||
let _ = value;
|
let _ = value;
|
||||||
@@ -201,9 +201,9 @@ where
|
|||||||
type Ok = Ok;
|
type Ok = Ok;
|
||||||
type Error = Error;
|
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
|
where
|
||||||
T: Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
let _ = key;
|
let _ = key;
|
||||||
let _ = value;
|
let _ = value;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
use lib::{Debug, Display};
|
use crate::lib::{Debug, Display};
|
||||||
|
|
||||||
/// Either a re-export of std::error::Error or a new identical trait, depending
|
/// Either a re-export of std::error::Error or a new identical trait, depending
|
||||||
/// on whether Serde's "std" feature is enabled.
|
/// on whether Serde's "std" feature is enabled.
|
||||||
@@ -9,7 +9,7 @@ use lib::{Debug, Display};
|
|||||||
/// generally provide their error types with a `std::error::Error` impl
|
/// generally provide their error types with a `std::error::Error` impl
|
||||||
/// directly:
|
/// directly:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// #[derive(Debug)]
|
/// #[derive(Debug)]
|
||||||
/// struct MySerError {...}
|
/// struct MySerError {...}
|
||||||
///
|
///
|
||||||
@@ -29,7 +29,7 @@ use lib::{Debug, Display};
|
|||||||
/// std = ["serde/std"]
|
/// std = ["serde/std"]
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// #[cfg(feature = "std")]
|
/// #[cfg(feature = "std")]
|
||||||
/// impl std::error::Error for MySerError {}
|
/// impl std::error::Error for MySerError {}
|
||||||
/// ```
|
/// ```
|
||||||
@@ -37,12 +37,12 @@ use lib::{Debug, Display};
|
|||||||
/// ... or else provide the std Error impl unconditionally via Serde's
|
/// ... or else provide the std Error impl unconditionally via Serde's
|
||||||
/// re-export:
|
/// re-export:
|
||||||
///
|
///
|
||||||
/// ```edition2018
|
/// ```edition2021
|
||||||
/// impl serde::ser::StdError for MySerError {}
|
/// impl serde::ser::StdError for MySerError {}
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Error: Debug + Display {
|
pub trait Error: Debug + Display {
|
||||||
/// The underlying cause of this error, if any.
|
/// The underlying cause of this error, if any.
|
||||||
fn source(&self) -> Option<&(Error + 'static)> {
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-8
@@ -1,17 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.165" # remember to update html_root_url
|
version = "1.0.228"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
categories = ["no-std"]
|
categories = ["no-std", "no-std::no-alloc"]
|
||||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||||
documentation = "https://serde.rs/derive.html"
|
documentation = "https://serde.rs/derive.html"
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["build.rs"]
|
||||||
homepage = "https://serde.rs"
|
homepage = "https://serde.rs"
|
||||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
keywords = ["serde", "serialization", "no_std", "derive"]
|
keywords = ["serde", "serialization", "no_std", "derive"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
readme = "crates-io.md"
|
readme = "crates-io.md"
|
||||||
repository = "https://github.com/serde-rs/serde"
|
repository = "https://github.com/serde-rs/serde"
|
||||||
rust-version = "1.56"
|
rust-version = "1.61"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
@@ -22,12 +23,20 @@ name = "serde_derive"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = { workspace = true, features = ["proc-macro"] }
|
||||||
quote = "1.0"
|
quote = { workspace = true, features = ["proc-macro"] }
|
||||||
syn = "2.0.21"
|
syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = { version = "1.0", path = "../serde" }
|
serde = { version = "1", path = "../serde" }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
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",
|
||||||
|
"--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)");
|
||||||
|
}
|
||||||
+11
-15
@@ -1,12 +1,9 @@
|
|||||||
use std::collections::HashSet;
|
use crate::internals::ast::{Container, Data};
|
||||||
|
use crate::internals::{attr, ungroup};
|
||||||
use syn;
|
|
||||||
use syn::punctuated::{Pair, Punctuated};
|
|
||||||
|
|
||||||
use internals::ast::{Container, Data};
|
|
||||||
use internals::{attr, ungroup};
|
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use syn::punctuated::{Pair, Punctuated};
|
||||||
|
use syn::Token;
|
||||||
|
|
||||||
// Remove the default from every type parameter because in the generated impls
|
// Remove the default from every type parameter because in the generated impls
|
||||||
// they look like associated types: "error: associated type bindings are not
|
// they look like associated types: "error: associated type bindings are not
|
||||||
@@ -147,6 +144,7 @@ pub fn with_bound(
|
|||||||
|
|
||||||
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
||||||
match ty {
|
match ty {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
||||||
syn::Type::BareFn(ty) => {
|
syn::Type::BareFn(ty) => {
|
||||||
for arg in &ty.inputs {
|
for arg in &ty.inputs {
|
||||||
@@ -184,7 +182,6 @@ pub fn with_bound(
|
|||||||
|
|
||||||
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
||||||
|
|
||||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,16 +196,13 @@ pub fn with_bound(
|
|||||||
syn::PathArguments::AngleBracketed(arguments) => {
|
syn::PathArguments::AngleBracketed(arguments) => {
|
||||||
for arg in &arguments.args {
|
for arg in &arguments.args {
|
||||||
match arg {
|
match arg {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
||||||
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
|
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
|
||||||
syn::GenericArgument::Lifetime(_)
|
syn::GenericArgument::Lifetime(_)
|
||||||
| syn::GenericArgument::Const(_)
|
| syn::GenericArgument::Const(_)
|
||||||
| syn::GenericArgument::AssocConst(_)
|
| syn::GenericArgument::AssocConst(_)
|
||||||
| syn::GenericArgument::Constraint(_) => {}
|
| syn::GenericArgument::Constraint(_) => {}
|
||||||
#[cfg_attr(
|
|
||||||
all(test, exhaustive),
|
|
||||||
deny(non_exhaustive_omitted_patterns)
|
|
||||||
)]
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,9 +225,11 @@ pub fn with_bound(
|
|||||||
|
|
||||||
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
||||||
match bound {
|
match bound {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
||||||
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
|
syn::TypeParamBound::Lifetime(_)
|
||||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
| syn::TypeParamBound::PreciseCapture(_)
|
||||||
|
| syn::TypeParamBound::Verbatim(_) => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+187
-2402
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
|
||||||
|
}
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
use syn;
|
|
||||||
use try;
|
|
||||||
|
|
||||||
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
|
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
|
||||||
let try_replacement = try::replacement();
|
|
||||||
|
|
||||||
let use_serde = match serde_path {
|
let use_serde = match serde_path {
|
||||||
Some(path) => quote! {
|
Some(path) => quote! {
|
||||||
use #path as _serde;
|
use #path as _serde;
|
||||||
@@ -18,10 +14,17 @@ pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> Token
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
#[allow(
|
||||||
|
non_upper_case_globals,
|
||||||
|
unused_attributes,
|
||||||
|
unused_qualifications,
|
||||||
|
clippy::absolute_paths,
|
||||||
|
)]
|
||||||
const _: () = {
|
const _: () = {
|
||||||
#use_serde
|
#use_serde
|
||||||
#try_replacement
|
|
||||||
|
_serde::__require_serde_not_serde_core!();
|
||||||
|
|
||||||
#code
|
#code
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::token;
|
use syn::{token, Token};
|
||||||
|
|
||||||
pub enum Fragment {
|
pub enum Fragment {
|
||||||
/// Tokens that can be used as an expression.
|
/// Tokens that can be used as an expression.
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
|
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
|
||||||
|
|
||||||
use internals::attr;
|
use crate::internals::{attr, check, Ctxt, Derive};
|
||||||
use internals::check;
|
use proc_macro2::Ident;
|
||||||
use internals::{Ctxt, Derive};
|
|
||||||
use syn;
|
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::Token;
|
||||||
|
|
||||||
/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
|
/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
|
||||||
/// parsed into an internal representation.
|
/// parsed into an internal representation.
|
||||||
@@ -64,13 +63,17 @@ impl<'a> Container<'a> {
|
|||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
item: &'a syn::DeriveInput,
|
item: &'a syn::DeriveInput,
|
||||||
derive: Derive,
|
derive: Derive,
|
||||||
|
private: &Ident,
|
||||||
) -> Option<Container<'a>> {
|
) -> 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 {
|
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) => {
|
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)
|
Data::Struct(style, fields)
|
||||||
}
|
}
|
||||||
syn::Data::Union(_) => {
|
syn::Data::Union(_) => {
|
||||||
@@ -79,35 +82,27 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut has_flatten = false;
|
|
||||||
match &mut data {
|
match &mut data {
|
||||||
Data::Enum(variants) => {
|
Data::Enum(variants) => {
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||||
for field in &mut variant.fields {
|
for field in &mut variant.fields {
|
||||||
if field.attrs.flatten() {
|
field.attrs.rename_by_rules(
|
||||||
has_flatten = true;
|
variant
|
||||||
}
|
.attrs
|
||||||
field
|
.rename_all_rules()
|
||||||
.attrs
|
.or(attrs.rename_all_fields_rules()),
|
||||||
.rename_by_rules(variant.attrs.rename_all_rules());
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(_, fields) => {
|
Data::Struct(_, fields) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if field.attrs.flatten() {
|
|
||||||
has_flatten = true;
|
|
||||||
}
|
|
||||||
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_flatten {
|
|
||||||
attrs.mark_has_flatten();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut item = Container {
|
let mut item = Container {
|
||||||
ident: item.ident.clone(),
|
ident: item.ident.clone(),
|
||||||
attrs,
|
attrs,
|
||||||
@@ -121,7 +116,7 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Data<'a> {
|
impl<'a> Data<'a> {
|
||||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> {
|
||||||
match self {
|
match self {
|
||||||
Data::Enum(variants) => {
|
Data::Enum(variants) => {
|
||||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||||
@@ -139,13 +134,19 @@ fn enum_from_ast<'a>(
|
|||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||||
container_default: &attr::Default,
|
container_default: &attr::Default,
|
||||||
|
private: &Ident,
|
||||||
) -> Vec<Variant<'a>> {
|
) -> Vec<Variant<'a>> {
|
||||||
let variants: Vec<Variant> = variants
|
let variants: Vec<Variant> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.map(|variant| {
|
.map(|variant| {
|
||||||
let attrs = attr::Variant::from_ast(cx, variant);
|
let attrs = attr::Variant::from_ast(cx, variant);
|
||||||
let (style, fields) =
|
let (style, fields) = struct_from_ast(
|
||||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
cx,
|
||||||
|
&variant.fields,
|
||||||
|
Some(&attrs),
|
||||||
|
container_default,
|
||||||
|
private,
|
||||||
|
);
|
||||||
Variant {
|
Variant {
|
||||||
ident: variant.ident.clone(),
|
ident: variant.ident.clone(),
|
||||||
attrs,
|
attrs,
|
||||||
@@ -175,19 +176,20 @@ fn struct_from_ast<'a>(
|
|||||||
fields: &'a syn::Fields,
|
fields: &'a syn::Fields,
|
||||||
attrs: Option<&attr::Variant>,
|
attrs: Option<&attr::Variant>,
|
||||||
container_default: &attr::Default,
|
container_default: &attr::Default,
|
||||||
|
private: &Ident,
|
||||||
) -> (Style, Vec<Field<'a>>) {
|
) -> (Style, Vec<Field<'a>>) {
|
||||||
match fields {
|
match fields {
|
||||||
syn::Fields::Named(fields) => (
|
syn::Fields::Named(fields) => (
|
||||||
Style::Struct,
|
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 => (
|
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
|
||||||
Style::Newtype,
|
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) => (
|
syn::Fields::Unnamed(fields) => (
|
||||||
Style::Tuple,
|
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()),
|
syn::Fields::Unit => (Style::Unit, Vec::new()),
|
||||||
}
|
}
|
||||||
@@ -198,6 +200,7 @@ fn fields_from_ast<'a>(
|
|||||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
fields: &'a Punctuated<syn::Field, Token![,]>,
|
||||||
attrs: Option<&attr::Variant>,
|
attrs: Option<&attr::Variant>,
|
||||||
container_default: &attr::Default,
|
container_default: &attr::Default,
|
||||||
|
private: &Ident,
|
||||||
) -> Vec<Field<'a>> {
|
) -> Vec<Field<'a>> {
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -207,7 +210,7 @@ fn fields_from_ast<'a>(
|
|||||||
Some(ident) => syn::Member::Named(ident.clone()),
|
Some(ident) => syn::Member::Named(ident.clone()),
|
||||||
None => syn::Member::Unnamed(i.into()),
|
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,
|
ty: &field.ty,
|
||||||
original: field,
|
original: field,
|
||||||
})
|
})
|
||||||
|
|||||||
+190
-164
@@ -1,15 +1,15 @@
|
|||||||
use internals::symbol::*;
|
use crate::internals::name::{MultiName, Name};
|
||||||
use internals::{ungroup, Ctxt};
|
use crate::internals::symbol::*;
|
||||||
|
use crate::internals::{ungroup, Ctxt};
|
||||||
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
|
use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use syn;
|
|
||||||
use syn::meta::ParseNestedMeta;
|
use syn::meta::ParseNestedMeta;
|
||||||
use syn::parse::ParseStream;
|
use syn::parse::ParseStream;
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::{token, Ident, Lifetime};
|
use syn::spanned::Spanned;
|
||||||
|
use syn::{token, Ident, Lifetime, Token};
|
||||||
|
|
||||||
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
|
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
|
||||||
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
|
// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and
|
||||||
@@ -19,9 +19,9 @@ use syn::{token, Ident, Lifetime};
|
|||||||
// user will see errors simultaneously for all bad attributes in the crate
|
// user will see errors simultaneously for all bad attributes in the crate
|
||||||
// rather than just the first.
|
// rather than just the first.
|
||||||
|
|
||||||
pub use internals::case::RenameRule;
|
pub use crate::internals::case::RenameRule;
|
||||||
|
|
||||||
struct Attr<'c, T> {
|
pub(crate) struct Attr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
tokens: TokenStream,
|
tokens: TokenStream,
|
||||||
@@ -62,7 +62,7 @@ impl<'c, T> Attr<'c, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(self) -> Option<T> {
|
pub(crate) fn get(self) -> Option<T> {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ impl<'c> BoolAttr<'c> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VecAttr<'c, T> {
|
pub(crate) struct VecAttr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: Symbol,
|
name: Symbol,
|
||||||
first_dup_tokens: TokenStream,
|
first_dup_tokens: TokenStream,
|
||||||
@@ -125,86 +125,40 @@ impl<'c, T> VecAttr<'c, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(self) -> Vec<T> {
|
pub(crate) fn get(self) -> Vec<T> {
|
||||||
self.values
|
self.values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Name {
|
fn unraw(ident: &Ident) -> Ident {
|
||||||
serialize: String,
|
Ident::new(ident.to_string().trim_start_matches("r#"), ident.span())
|
||||||
serialize_renamed: bool,
|
|
||||||
deserialize: String,
|
|
||||||
deserialize_renamed: bool,
|
|
||||||
deserialize_aliases: Vec<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 deserialize_aliases = match de_aliases {
|
|
||||||
Some(de_aliases) => {
|
|
||||||
let mut alias_list = BTreeSet::new();
|
|
||||||
for alias_name in de_aliases.get() {
|
|
||||||
alias_list.insert(alias_name);
|
|
||||||
}
|
|
||||||
alias_list.into_iter().collect()
|
|
||||||
}
|
|
||||||
None => Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the container name for the container when serializing.
|
|
||||||
pub fn serialize_name(&self) -> String {
|
|
||||||
self.serialize.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the container name for the container when deserializing.
|
|
||||||
pub fn deserialize_name(&self) -> String {
|
|
||||||
self.deserialize.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_aliases(&self) -> Vec<String> {
|
|
||||||
let mut aliases = self.deserialize_aliases.clone();
|
|
||||||
let main_name = self.deserialize_name();
|
|
||||||
if !aliases.contains(&main_name) {
|
|
||||||
aliases.push(main_name);
|
|
||||||
}
|
|
||||||
aliases
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub struct RenameAllRules {
|
pub struct RenameAllRules {
|
||||||
serialize: RenameRule,
|
pub serialize: RenameRule,
|
||||||
deserialize: RenameRule,
|
pub deserialize: RenameRule,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenameAllRules {
|
||||||
|
/// Returns a new `RenameAllRules` with the individual rules of `self` and
|
||||||
|
/// `other_rules` joined by `RenameRules::or`.
|
||||||
|
pub fn or(self, other_rules: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
serialize: self.serialize.or(other_rules.serialize),
|
||||||
|
deserialize: self.deserialize.or(other_rules.deserialize),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents struct or enum attribute information.
|
/// Represents struct or enum attribute information.
|
||||||
pub struct Container {
|
pub struct Container {
|
||||||
name: Name,
|
name: MultiName,
|
||||||
transparent: bool,
|
transparent: bool,
|
||||||
deny_unknown_fields: bool,
|
deny_unknown_fields: bool,
|
||||||
default: Default,
|
default: Default,
|
||||||
rename_all_rules: RenameAllRules,
|
rename_all_rules: RenameAllRules,
|
||||||
|
rename_all_fields_rules: RenameAllRules,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
tag: TagType,
|
tag: TagType,
|
||||||
@@ -213,11 +167,11 @@ pub struct Container {
|
|||||||
type_into: Option<syn::Type>,
|
type_into: Option<syn::Type>,
|
||||||
remote: Option<syn::Path>,
|
remote: Option<syn::Path>,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
has_flatten: bool,
|
|
||||||
serde_path: Option<syn::Path>,
|
serde_path: Option<syn::Path>,
|
||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
/// Error message generated when type can't be deserialized
|
/// Error message generated when type can't be deserialized
|
||||||
expecting: Option<String>,
|
expecting: Option<String>,
|
||||||
|
non_exhaustive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Styles of representing an enum.
|
/// Styles of representing an enum.
|
||||||
@@ -288,6 +242,8 @@ impl Container {
|
|||||||
let mut default = Attr::none(cx, DEFAULT);
|
let mut default = Attr::none(cx, DEFAULT);
|
||||||
let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL);
|
let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL);
|
||||||
let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL);
|
let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL);
|
||||||
|
let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS);
|
||||||
|
let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS);
|
||||||
let mut ser_bound = Attr::none(cx, BOUND);
|
let mut ser_bound = Attr::none(cx, BOUND);
|
||||||
let mut de_bound = Attr::none(cx, BOUND);
|
let mut de_bound = Attr::none(cx, BOUND);
|
||||||
let mut untagged = BoolAttr::none(cx, UNTAGGED);
|
let mut untagged = BoolAttr::none(cx, UNTAGGED);
|
||||||
@@ -301,9 +257,12 @@ impl Container {
|
|||||||
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
|
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
|
||||||
let mut serde_path = Attr::none(cx, CRATE);
|
let mut serde_path = Attr::none(cx, CRATE);
|
||||||
let mut expecting = Attr::none(cx, EXPECTING);
|
let mut expecting = Attr::none(cx, EXPECTING);
|
||||||
|
let mut non_exhaustive = false;
|
||||||
|
|
||||||
for attr in &item.attrs {
|
for attr in &item.attrs {
|
||||||
if attr.path() != SERDE {
|
if attr.path() != SERDE {
|
||||||
|
non_exhaustive |=
|
||||||
|
matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,8 +277,8 @@ impl Container {
|
|||||||
// #[serde(rename = "foo")]
|
// #[serde(rename = "foo")]
|
||||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||||
let (ser, de) = get_renames(cx, RENAME, &meta)?;
|
let (ser, de) = get_renames(cx, RENAME, &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));
|
||||||
de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value));
|
de_name.set_opt(&meta.path, de.as_ref().map(Name::from));
|
||||||
} else if meta.path == RENAME_ALL {
|
} else if meta.path == RENAME_ALL {
|
||||||
// #[serde(rename_all = "foo")]
|
// #[serde(rename_all = "foo")]
|
||||||
// #[serde(rename_all(serialize = "foo", deserialize = "bar"))]
|
// #[serde(rename_all(serialize = "foo", deserialize = "bar"))]
|
||||||
@@ -341,6 +300,44 @@ impl Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if meta.path == RENAME_ALL_FIELDS {
|
||||||
|
// #[serde(rename_all_fields = "foo")]
|
||||||
|
// #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))]
|
||||||
|
let one_name = meta.input.peek(Token![=]);
|
||||||
|
let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?;
|
||||||
|
|
||||||
|
match item.data {
|
||||||
|
syn::Data::Enum(_) => {
|
||||||
|
if let Some(ser) = ser {
|
||||||
|
match RenameRule::from_str(&ser.value()) {
|
||||||
|
Ok(rename_rule) => {
|
||||||
|
rename_all_fields_ser_rule.set(&meta.path, rename_rule);
|
||||||
|
}
|
||||||
|
Err(err) => cx.error_spanned_by(ser, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(de) = de {
|
||||||
|
match RenameRule::from_str(&de.value()) {
|
||||||
|
Ok(rename_rule) => {
|
||||||
|
rename_all_fields_de_rule.set(&meta.path, rename_rule);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
if !one_name {
|
||||||
|
cx.error_spanned_by(de, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::Data::Struct(_) => {
|
||||||
|
let msg = "#[serde(rename_all_fields)] can only be used on enums";
|
||||||
|
cx.syn_error(meta.error(msg));
|
||||||
|
}
|
||||||
|
syn::Data::Union(_) => {
|
||||||
|
let msg = "#[serde(rename_all_fields)] can only be used on enums";
|
||||||
|
cx.syn_error(meta.error(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if meta.path == TRANSPARENT {
|
} else if meta.path == TRANSPARENT {
|
||||||
// #[serde(transparent)]
|
// #[serde(transparent)]
|
||||||
transparent.set_true(meta.path);
|
transparent.set_true(meta.path);
|
||||||
@@ -353,21 +350,21 @@ impl Container {
|
|||||||
if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
|
if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
|
||||||
match &item.data {
|
match &item.data {
|
||||||
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
|
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
|
||||||
syn::Fields::Named(_) => {
|
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
|
||||||
default.set(&meta.path, Default::Path(path));
|
default.set(&meta.path, Default::Path(path));
|
||||||
}
|
}
|
||||||
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
|
syn::Fields::Unit => {
|
||||||
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
|
let msg = "#[serde(default = \"...\")] can only be used on structs that have fields";
|
||||||
cx.error_spanned_by(fields, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
|
syn::Data::Enum(_) => {
|
||||||
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
|
let msg = "#[serde(default = \"...\")] can only be used on structs";
|
||||||
cx.error_spanned_by(enum_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
|
syn::Data::Union(_) => {
|
||||||
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
|
let msg = "#[serde(default = \"...\")] can only be used on structs";
|
||||||
cx.error_spanned_by(union_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,21 +372,21 @@ impl Container {
|
|||||||
// #[serde(default)]
|
// #[serde(default)]
|
||||||
match &item.data {
|
match &item.data {
|
||||||
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
|
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
|
||||||
syn::Fields::Named(_) => {
|
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
|
||||||
default.set(meta.path, Default::Default);
|
default.set(meta.path, Default::Default);
|
||||||
}
|
}
|
||||||
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
|
syn::Fields::Unit => {
|
||||||
let msg = "#[serde(default)] can only be used on structs with named fields";
|
let msg = "#[serde(default)] can only be used on structs that have fields";
|
||||||
cx.error_spanned_by(fields, msg);
|
cx.error_spanned_by(fields, msg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
|
syn::Data::Enum(_) => {
|
||||||
let msg = "#[serde(default)] can only be used on structs with named fields";
|
let msg = "#[serde(default)] can only be used on structs";
|
||||||
cx.error_spanned_by(enum_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
|
syn::Data::Union(_) => {
|
||||||
let msg = "#[serde(default)] can only be used on structs with named fields";
|
let msg = "#[serde(default)] can only be used on structs";
|
||||||
cx.error_spanned_by(union_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,13 +402,13 @@ impl Container {
|
|||||||
syn::Data::Enum(_) => {
|
syn::Data::Enum(_) => {
|
||||||
untagged.set_true(&meta.path);
|
untagged.set_true(&meta.path);
|
||||||
}
|
}
|
||||||
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
|
syn::Data::Struct(_) => {
|
||||||
let msg = "#[serde(untagged)] can only be used on enums";
|
let msg = "#[serde(untagged)] can only be used on enums";
|
||||||
cx.error_spanned_by(struct_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
|
syn::Data::Union(_) => {
|
||||||
let msg = "#[serde(untagged)] can only be used on enums";
|
let msg = "#[serde(untagged)] can only be used on enums";
|
||||||
cx.error_spanned_by(union_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if meta.path == TAG {
|
} else if meta.path == TAG {
|
||||||
@@ -427,12 +424,12 @@ impl Container {
|
|||||||
}
|
}
|
||||||
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
|
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
|
||||||
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
|
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
|
||||||
cx.error_spanned_by(fields, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
|
syn::Data::Union(_) => {
|
||||||
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
|
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
|
||||||
cx.error_spanned_by(union_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,13 +440,13 @@ impl Container {
|
|||||||
syn::Data::Enum(_) => {
|
syn::Data::Enum(_) => {
|
||||||
content.set(&meta.path, s.value());
|
content.set(&meta.path, s.value());
|
||||||
}
|
}
|
||||||
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
|
syn::Data::Struct(_) => {
|
||||||
let msg = "#[serde(content = \"...\")] can only be used on enums";
|
let msg = "#[serde(content = \"...\")] can only be used on enums";
|
||||||
cx.error_spanned_by(struct_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
|
syn::Data::Union(_) => {
|
||||||
let msg = "#[serde(content = \"...\")] can only be used on enums";
|
let msg = "#[serde(content = \"...\")] can only be used on enums";
|
||||||
cx.error_spanned_by(union_token, msg);
|
cx.syn_error(meta.error(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,7 +517,7 @@ impl Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
transparent: transparent.get(),
|
||||||
deny_unknown_fields: deny_unknown_fields.get(),
|
deny_unknown_fields: deny_unknown_fields.get(),
|
||||||
default: default.get().unwrap_or(Default::None),
|
default: default.get().unwrap_or(Default::None),
|
||||||
@@ -528,6 +525,10 @@ impl Container {
|
|||||||
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
||||||
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
||||||
},
|
},
|
||||||
|
rename_all_fields_rules: RenameAllRules {
|
||||||
|
serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None),
|
||||||
|
deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None),
|
||||||
|
},
|
||||||
ser_bound: ser_bound.get(),
|
ser_bound: ser_bound.get(),
|
||||||
de_bound: de_bound.get(),
|
de_bound: de_bound.get(),
|
||||||
tag: decide_tag(cx, item, untagged, internal_tag, content),
|
tag: decide_tag(cx, item, untagged, internal_tag, content),
|
||||||
@@ -536,19 +537,23 @@ impl Container {
|
|||||||
type_into: type_into.get(),
|
type_into: type_into.get(),
|
||||||
remote: remote.get(),
|
remote: remote.get(),
|
||||||
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
||||||
has_flatten: false,
|
|
||||||
serde_path: serde_path.get(),
|
serde_path: serde_path.get(),
|
||||||
is_packed,
|
is_packed,
|
||||||
expecting: expecting.get(),
|
expecting: expecting.get(),
|
||||||
|
non_exhaustive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &Name {
|
pub fn name(&self) -> &MultiName {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename_all_rules(&self) -> &RenameAllRules {
|
pub fn rename_all_rules(&self) -> RenameAllRules {
|
||||||
&self.rename_all_rules
|
self.rename_all_rules
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rename_all_fields_rules(&self) -> RenameAllRules {
|
||||||
|
self.rename_all_fields_rules
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transparent(&self) -> bool {
|
pub fn transparent(&self) -> bool {
|
||||||
@@ -599,28 +604,19 @@ impl Container {
|
|||||||
self.identifier
|
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> {
|
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
|
||||||
self.serde_path.as_ref()
|
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.
|
/// Error message generated when type can't be deserialized.
|
||||||
/// If `None`, default message will be used
|
/// If `None`, default message will be used
|
||||||
pub fn expecting(&self) -> Option<&str> {
|
pub fn expecting(&self) -> Option<&str> {
|
||||||
self.expecting.as_ref().map(String::as_ref)
|
self.expecting.as_ref().map(String::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn non_exhaustive(&self) -> bool {
|
||||||
|
self.non_exhaustive
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decide_tag(
|
fn decide_tag(
|
||||||
@@ -656,7 +652,7 @@ fn decide_tag(
|
|||||||
}
|
}
|
||||||
TagType::Internal { tag }
|
TagType::Internal { tag }
|
||||||
}
|
}
|
||||||
(Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
|
(Some((untagged_tokens, ())), Some((tag_tokens, _)), None) => {
|
||||||
let msg = "enum cannot be both untagged and internally tagged";
|
let msg = "enum cannot be both untagged and internally tagged";
|
||||||
cx.error_spanned_by(untagged_tokens, msg);
|
cx.error_spanned_by(untagged_tokens, msg);
|
||||||
cx.error_spanned_by(tag_tokens, msg);
|
cx.error_spanned_by(tag_tokens, msg);
|
||||||
@@ -667,14 +663,14 @@ fn decide_tag(
|
|||||||
cx.error_spanned_by(content_tokens, msg);
|
cx.error_spanned_by(content_tokens, msg);
|
||||||
TagType::External
|
TagType::External
|
||||||
}
|
}
|
||||||
(Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
|
(Some((untagged_tokens, ())), None, Some((content_tokens, _))) => {
|
||||||
let msg = "untagged enum cannot have #[serde(content = \"...\")]";
|
let msg = "untagged enum cannot have #[serde(content = \"...\")]";
|
||||||
cx.error_spanned_by(untagged_tokens, msg);
|
cx.error_spanned_by(untagged_tokens, msg);
|
||||||
cx.error_spanned_by(content_tokens, msg);
|
cx.error_spanned_by(content_tokens, msg);
|
||||||
TagType::External
|
TagType::External
|
||||||
}
|
}
|
||||||
(None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content },
|
(None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content },
|
||||||
(Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => {
|
(Some((untagged_tokens, ())), Some((tag_tokens, _)), Some((content_tokens, _))) => {
|
||||||
let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]";
|
let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]";
|
||||||
cx.error_spanned_by(untagged_tokens, msg);
|
cx.error_spanned_by(untagged_tokens, msg);
|
||||||
cx.error_spanned_by(tag_tokens, msg);
|
cx.error_spanned_by(tag_tokens, msg);
|
||||||
@@ -696,7 +692,7 @@ fn decide_identifier(
|
|||||||
variant_identifier.0.get_with_tokens(),
|
variant_identifier.0.get_with_tokens(),
|
||||||
) {
|
) {
|
||||||
(_, None, None) => Identifier::No,
|
(_, None, None) => Identifier::No,
|
||||||
(_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
|
(_, Some((field_identifier_tokens, ())), Some((variant_identifier_tokens, ()))) => {
|
||||||
let msg =
|
let msg =
|
||||||
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set";
|
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set";
|
||||||
cx.error_spanned_by(field_identifier_tokens, msg);
|
cx.error_spanned_by(field_identifier_tokens, msg);
|
||||||
@@ -730,7 +726,7 @@ fn decide_identifier(
|
|||||||
|
|
||||||
/// Represents variant attribute information
|
/// Represents variant attribute information
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
name: Name,
|
name: MultiName,
|
||||||
rename_all_rules: RenameAllRules,
|
rename_all_rules: RenameAllRules,
|
||||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||||
@@ -781,15 +777,15 @@ impl Variant {
|
|||||||
// #[serde(rename = "foo")]
|
// #[serde(rename = "foo")]
|
||||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||||
let (ser, de) = get_multiple_renames(cx, &meta)?;
|
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 {
|
for de_value in de {
|
||||||
de_name.set_if_none(de_value.value());
|
de_name.set_if_none(Name::from(&de_value));
|
||||||
de_aliases.insert(&meta.path, de_value.value());
|
de_aliases.insert(&meta.path, Name::from(&de_value));
|
||||||
}
|
}
|
||||||
} else if meta.path == ALIAS {
|
} else if meta.path == ALIAS {
|
||||||
// #[serde(alias = "foo")]
|
// #[serde(alias = "foo")]
|
||||||
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
|
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 {
|
} else if meta.path == RENAME_ALL {
|
||||||
// #[serde(rename_all = "foo")]
|
// #[serde(rename_all = "foo")]
|
||||||
@@ -838,13 +834,13 @@ impl Variant {
|
|||||||
ser_path
|
ser_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("serialize", Span::call_site()).into());
|
.push(Ident::new("serialize", ser_path.span()).into());
|
||||||
serialize_with.set(&meta.path, ser_path);
|
serialize_with.set(&meta.path, ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path
|
de_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
.push(Ident::new("deserialize", de_path.span()).into());
|
||||||
deserialize_with.set(&meta.path, de_path);
|
deserialize_with.set(&meta.path, de_path);
|
||||||
}
|
}
|
||||||
} else if meta.path == SERIALIZE_WITH {
|
} else if meta.path == SERIALIZE_WITH {
|
||||||
@@ -896,7 +892,12 @@ impl Variant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
rename_all_rules: RenameAllRules {
|
||||||
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
|
||||||
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
|
||||||
@@ -913,25 +914,31 @@ impl Variant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &Name {
|
pub fn name(&self) -> &MultiName {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aliases(&self) -> Vec<String> {
|
pub fn aliases(&self) -> &BTreeSet<Name> {
|
||||||
self.name.deserialize_aliases()
|
self.name.deserialize_aliases()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
|
||||||
if !self.name.serialize_renamed {
|
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 {
|
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
|
||||||
|
.insert(self.name.deserialize.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename_all_rules(&self) -> &RenameAllRules {
|
pub fn rename_all_rules(&self) -> RenameAllRules {
|
||||||
&self.rename_all_rules
|
self.rename_all_rules
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||||
@@ -969,7 +976,7 @@ impl Variant {
|
|||||||
|
|
||||||
/// Represents field attribute information
|
/// Represents field attribute information
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
name: Name,
|
name: MultiName,
|
||||||
skip_serializing: bool,
|
skip_serializing: bool,
|
||||||
skip_deserializing: bool,
|
skip_deserializing: bool,
|
||||||
skip_serializing_if: Option<syn::ExprPath>,
|
skip_serializing_if: Option<syn::ExprPath>,
|
||||||
@@ -1011,6 +1018,7 @@ impl Field {
|
|||||||
field: &syn::Field,
|
field: &syn::Field,
|
||||||
attrs: Option<&Variant>,
|
attrs: Option<&Variant>,
|
||||||
container_default: &Default,
|
container_default: &Default,
|
||||||
|
private: &Ident,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut ser_name = Attr::none(cx, RENAME);
|
let mut ser_name = Attr::none(cx, RENAME);
|
||||||
let mut de_name = Attr::none(cx, RENAME);
|
let mut de_name = Attr::none(cx, RENAME);
|
||||||
@@ -1028,8 +1036,11 @@ impl Field {
|
|||||||
let mut flatten = BoolAttr::none(cx, FLATTEN);
|
let mut flatten = BoolAttr::none(cx, FLATTEN);
|
||||||
|
|
||||||
let ident = match &field.ident {
|
let ident = match &field.ident {
|
||||||
Some(ident) => unraw(ident),
|
Some(ident) => Name::from(&unraw(ident)),
|
||||||
None => index.to_string(),
|
None => Name {
|
||||||
|
value: index.to_string(),
|
||||||
|
span: Span::call_site(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
|
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
|
||||||
@@ -1065,15 +1076,15 @@ impl Field {
|
|||||||
// #[serde(rename = "foo")]
|
// #[serde(rename = "foo")]
|
||||||
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
// #[serde(rename(serialize = "foo", deserialize = "bar"))]
|
||||||
let (ser, de) = get_multiple_renames(cx, &meta)?;
|
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 {
|
for de_value in de {
|
||||||
de_name.set_if_none(de_value.value());
|
de_name.set_if_none(Name::from(&de_value));
|
||||||
de_aliases.insert(&meta.path, de_value.value());
|
de_aliases.insert(&meta.path, Name::from(&de_value));
|
||||||
}
|
}
|
||||||
} else if meta.path == ALIAS {
|
} else if meta.path == ALIAS {
|
||||||
// #[serde(alias = "foo")]
|
// #[serde(alias = "foo")]
|
||||||
if let Some(s) = get_lit_str(cx, ALIAS, &meta)? {
|
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 {
|
} else if meta.path == DEFAULT {
|
||||||
if meta.input.peek(Token![=]) {
|
if meta.input.peek(Token![=]) {
|
||||||
@@ -1117,13 +1128,13 @@ impl Field {
|
|||||||
ser_path
|
ser_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("serialize", Span::call_site()).into());
|
.push(Ident::new("serialize", ser_path.span()).into());
|
||||||
serialize_with.set(&meta.path, ser_path);
|
serialize_with.set(&meta.path, ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path
|
de_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
.push(Ident::new("deserialize", de_path.span()).into());
|
||||||
deserialize_with.set(&meta.path, de_path);
|
deserialize_with.set(&meta.path, de_path);
|
||||||
}
|
}
|
||||||
} else if meta.path == BOUND {
|
} else if meta.path == BOUND {
|
||||||
@@ -1201,7 +1212,7 @@ impl Field {
|
|||||||
};
|
};
|
||||||
let span = Span::call_site();
|
let span = Span::call_site();
|
||||||
path.segments.push(Ident::new("_serde", span).into());
|
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("de", span).into());
|
||||||
path.segments
|
path.segments
|
||||||
.push(Ident::new("borrow_cow_str", span).into());
|
.push(Ident::new("borrow_cow_str", span).into());
|
||||||
@@ -1218,7 +1229,7 @@ impl Field {
|
|||||||
};
|
};
|
||||||
let span = Span::call_site();
|
let span = Span::call_site();
|
||||||
path.segments.push(Ident::new("_serde", span).into());
|
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("de", span).into());
|
||||||
path.segments
|
path.segments
|
||||||
.push(Ident::new("borrow_cow_bytes", span).into());
|
.push(Ident::new("borrow_cow_bytes", span).into());
|
||||||
@@ -1236,7 +1247,7 @@ impl Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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_serializing: skip_serializing.get(),
|
||||||
skip_deserializing: skip_deserializing.get(),
|
skip_deserializing: skip_deserializing.get(),
|
||||||
skip_serializing_if: skip_serializing_if.get(),
|
skip_serializing_if: skip_serializing_if.get(),
|
||||||
@@ -1252,21 +1263,26 @@ impl Field {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &Name {
|
pub fn name(&self) -> &MultiName {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aliases(&self) -> Vec<String> {
|
pub fn aliases(&self) -> &BTreeSet<Name> {
|
||||||
self.name.deserialize_aliases()
|
self.name.deserialize_aliases()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
|
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
|
||||||
if !self.name.serialize_renamed {
|
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 {
|
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
|
||||||
|
.insert(self.name.deserialize.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_serializing(&self) -> bool {
|
pub fn skip_serializing(&self) -> bool {
|
||||||
@@ -1418,6 +1434,13 @@ fn get_lit_str2(
|
|||||||
..
|
..
|
||||||
}) = value
|
}) = value
|
||||||
{
|
{
|
||||||
|
let suffix = lit.suffix();
|
||||||
|
if !suffix.is_empty() {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
format!("unexpected suffix `{}` on string literal", suffix),
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(Some(lit.clone()))
|
Ok(Some(lit.clone()))
|
||||||
} else {
|
} else {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
@@ -1705,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.
|
// attribute on the field so there must be at least one borrowable lifetime.
|
||||||
fn borrowable_lifetimes(
|
fn borrowable_lifetimes(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
name: &str,
|
name: &Name,
|
||||||
field: &syn::Field,
|
field: &syn::Field,
|
||||||
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
||||||
let mut lifetimes = BTreeSet::new();
|
let mut lifetimes = BTreeSet::new();
|
||||||
@@ -1721,6 +1744,7 @@ fn borrowable_lifetimes(
|
|||||||
|
|
||||||
fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
||||||
match ty {
|
match ty {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
syn::Type::Slice(ty) => {
|
syn::Type::Slice(ty) => {
|
||||||
collect_lifetimes(&ty.elem, out);
|
collect_lifetimes(&ty.elem, out);
|
||||||
}
|
}
|
||||||
@@ -1756,7 +1780,10 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
|||||||
syn::GenericArgument::AssocType(binding) => {
|
syn::GenericArgument::AssocType(binding) => {
|
||||||
collect_lifetimes(&binding.ty, out);
|
collect_lifetimes(&binding.ty, out);
|
||||||
}
|
}
|
||||||
_ => {}
|
syn::GenericArgument::Const(_)
|
||||||
|
| syn::GenericArgument::AssocConst(_)
|
||||||
|
| syn::GenericArgument::Constraint(_)
|
||||||
|
| _ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1778,7 +1805,6 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
|
|||||||
| syn::Type::Infer(_)
|
| syn::Type::Infer(_)
|
||||||
| syn::Type::Verbatim(_) => {}
|
| syn::Type::Verbatim(_) => {}
|
||||||
|
|
||||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
|
//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
|
||||||
//! case of the source (e.g. `my-field`, `MY_FIELD`).
|
//! case of the source (e.g. `my-field`, `MY_FIELD`).
|
||||||
|
|
||||||
// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726
|
|
||||||
#[allow(deprecated, unused_imports)]
|
|
||||||
use std::ascii::AsciiExt;
|
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Display};
|
|
||||||
|
|
||||||
use self::RenameRule::*;
|
use self::RenameRule::*;
|
||||||
|
use std::fmt::{self, Debug, Display};
|
||||||
|
|
||||||
/// The different possible ways to change case of fields in a struct, or variants in an enum.
|
/// The different possible ways to change case of fields in a struct, or variants in an enum.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
@@ -59,8 +54,8 @@ impl RenameRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
||||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
pub fn apply_to_variant(self, variant: &str) -> String {
|
||||||
match *self {
|
match self {
|
||||||
None | PascalCase => variant.to_owned(),
|
None | PascalCase => variant.to_owned(),
|
||||||
LowerCase => variant.to_ascii_lowercase(),
|
LowerCase => variant.to_ascii_lowercase(),
|
||||||
UpperCase => variant.to_ascii_uppercase(),
|
UpperCase => variant.to_ascii_uppercase(),
|
||||||
@@ -84,8 +79,8 @@ impl RenameRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a renaming rule to a struct field, returning the version expected in the source.
|
/// Apply a renaming rule to a struct field, returning the version expected in the source.
|
||||||
pub fn apply_to_field(&self, field: &str) -> String {
|
pub fn apply_to_field(self, field: &str) -> String {
|
||||||
match *self {
|
match self {
|
||||||
None | LowerCase | SnakeCase => field.to_owned(),
|
None | LowerCase | SnakeCase => field.to_owned(),
|
||||||
UpperCase => field.to_ascii_uppercase(),
|
UpperCase => field.to_ascii_uppercase(),
|
||||||
PascalCase => {
|
PascalCase => {
|
||||||
@@ -112,6 +107,14 @@ impl RenameRule {
|
|||||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
|
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise.
|
||||||
|
pub fn or(self, rule_b: Self) -> Self {
|
||||||
|
match self {
|
||||||
|
None => rule_b,
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParseError<'a> {
|
pub struct ParseError<'a> {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use internals::ast::{Container, Data, Field, Style};
|
use crate::internals::ast::{Container, Data, Field, Style};
|
||||||
use internals::attr::{Identifier, TagType};
|
use crate::internals::attr::{Default, Identifier, TagType};
|
||||||
use internals::{ungroup, Ctxt, Derive};
|
use crate::internals::{ungroup, Ctxt, Derive};
|
||||||
use syn::{Member, Type};
|
use syn::{Member, Type};
|
||||||
|
|
||||||
// Cross-cutting checks that require looking at more than a single attrs object.
|
// Cross-cutting checks that require looking at more than a single attrs object.
|
||||||
// Simpler checks should happen when parsing and building the attrs.
|
// Simpler checks should happen when parsing and building the attrs.
|
||||||
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
||||||
|
check_default_on_tuple(cx, cont);
|
||||||
check_remote_generic(cx, cont);
|
check_remote_generic(cx, cont);
|
||||||
check_getter(cx, cont);
|
check_getter(cx, cont);
|
||||||
check_flatten(cx, cont);
|
check_flatten(cx, cont);
|
||||||
@@ -17,6 +18,39 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
check_from_and_try_from(cx, cont);
|
check_from_and_try_from(cx, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If some field of a tuple struct is marked #[serde(default)] then all fields
|
||||||
|
// after it must also be marked with that attribute, or the struct must have a
|
||||||
|
// container-level serde(default) attribute. A field's default value is only
|
||||||
|
// used for tuple fields if the sequence is exhausted at that point; that means
|
||||||
|
// all subsequent fields will fail to deserialize if they don't have their own
|
||||||
|
// default.
|
||||||
|
fn check_default_on_tuple(cx: &Ctxt, cont: &Container) {
|
||||||
|
if let Default::None = cont.attrs.default() {
|
||||||
|
if let Data::Struct(Style::Tuple, fields) = &cont.data {
|
||||||
|
let mut first_default_index = None;
|
||||||
|
for (i, field) in fields.iter().enumerate() {
|
||||||
|
// Skipped fields automatically get the #[serde(default)]
|
||||||
|
// attribute. We are interested only on non-skipped fields here.
|
||||||
|
if field.attrs.skip_deserializing() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Default::None = field.attrs.default() {
|
||||||
|
if let Some(first) = first_default_index {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
field.ty,
|
||||||
|
format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if first_default_index.is_none() {
|
||||||
|
first_default_index = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remote derive definition type must have either all of the generics of the
|
// Remote derive definition type must have either all of the generics of the
|
||||||
// remote type:
|
// remote type:
|
||||||
//
|
//
|
||||||
@@ -284,19 +318,24 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
|||||||
for variant in variants {
|
for variant in variants {
|
||||||
match variant.style {
|
match variant.style {
|
||||||
Style::Struct => {
|
Style::Struct => {
|
||||||
|
if variant.attrs.untagged() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for field in &variant.fields {
|
for field in &variant.fields {
|
||||||
let check_ser = !field.attrs.skip_serializing();
|
let check_ser =
|
||||||
let check_de = !field.attrs.skip_deserializing();
|
!(field.attrs.skip_serializing() || variant.attrs.skip_serializing());
|
||||||
|
let check_de =
|
||||||
|
!(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing());
|
||||||
let name = field.attrs.name();
|
let name = field.attrs.name();
|
||||||
let ser_name = name.serialize_name();
|
let ser_name = name.serialize_name();
|
||||||
|
|
||||||
if check_ser && ser_name == tag {
|
if check_ser && ser_name.value == tag {
|
||||||
diagnose_conflict();
|
diagnose_conflict();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for de_name in field.attrs.aliases() {
|
for de_name in field.attrs.aliases() {
|
||||||
if check_de && de_name == tag {
|
if check_de && de_name.value == tag {
|
||||||
diagnose_conflict();
|
diagnose_conflict();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use quote::ToTokens;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use syn;
|
|
||||||
|
|
||||||
/// A type to collect errors together and format them.
|
/// A type to collect errors together and format them.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
pub mod name;
|
||||||
mod ctxt;
|
|
||||||
pub use self::ctxt::Ctxt;
|
|
||||||
|
|
||||||
mod receiver;
|
|
||||||
pub use self::receiver::replace_receiver;
|
|
||||||
|
|
||||||
mod case;
|
mod case;
|
||||||
mod check;
|
mod check;
|
||||||
|
mod ctxt;
|
||||||
|
mod receiver;
|
||||||
mod respan;
|
mod respan;
|
||||||
mod symbol;
|
mod symbol;
|
||||||
|
|
||||||
use syn::Type;
|
use syn::Type;
|
||||||
|
|
||||||
|
pub use self::ctxt::Ctxt;
|
||||||
|
pub use self::receiver::replace_receiver;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum Derive {
|
pub enum Derive {
|
||||||
Serialize,
|
Serialize,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
use internals::respan::respan;
|
use crate::internals::respan::respan;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
|
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
|
||||||
Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate,
|
Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn replace_receiver(input: &mut DeriveInput) {
|
pub fn replace_receiver(input: &mut DeriveInput) {
|
||||||
@@ -49,7 +48,7 @@ impl ReplaceReceiver<'_> {
|
|||||||
|
|
||||||
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
|
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();
|
path.segments = segments.into_pairs().skip(1).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ impl ReplaceReceiver<'_> {
|
|||||||
self.visit_type_mut_impl(ty);
|
self.visit_type_mut_impl(ty);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
*ty = self.self_ty(span).into();
|
*ty = Type::Path(self.self_ty(span));
|
||||||
}
|
}
|
||||||
|
|
||||||
// `Self::Assoc` -> `<Receiver>::Assoc`
|
// `Self::Assoc` -> `<Receiver>::Assoc`
|
||||||
@@ -107,6 +106,7 @@ impl ReplaceReceiver<'_> {
|
|||||||
|
|
||||||
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
|
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
|
||||||
match ty {
|
match ty {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
Type::Array(ty) => {
|
Type::Array(ty) => {
|
||||||
self.visit_type_mut(&mut ty.elem);
|
self.visit_type_mut(&mut ty.elem);
|
||||||
self.visit_expr_mut(&mut ty.len);
|
self.visit_expr_mut(&mut ty.len);
|
||||||
@@ -147,7 +147,6 @@ impl ReplaceReceiver<'_> {
|
|||||||
|
|
||||||
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
|
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) => {
|
PathArguments::AngleBracketed(arguments) => {
|
||||||
for arg in &mut arguments.args {
|
for arg in &mut arguments.args {
|
||||||
match arg {
|
match arg {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
GenericArgument::Type(arg) => self.visit_type_mut(arg),
|
GenericArgument::Type(arg) => self.visit_type_mut(arg),
|
||||||
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
|
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
|
||||||
GenericArgument::Lifetime(_)
|
GenericArgument::Lifetime(_)
|
||||||
| GenericArgument::Const(_)
|
| GenericArgument::Const(_)
|
||||||
| GenericArgument::AssocConst(_)
|
| GenericArgument::AssocConst(_)
|
||||||
| GenericArgument::Constraint(_) => {}
|
| 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) {
|
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
|
||||||
match bound {
|
match bound {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
|
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
|
||||||
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
|
TypeParamBound::Lifetime(_)
|
||||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
| TypeParamBound::PreciseCapture(_)
|
||||||
|
| TypeParamBound::Verbatim(_) => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,6 +229,7 @@ impl ReplaceReceiver<'_> {
|
|||||||
if let Some(where_clause) = &mut generics.where_clause {
|
if let Some(where_clause) = &mut generics.where_clause {
|
||||||
for predicate in &mut where_clause.predicates {
|
for predicate in &mut where_clause.predicates {
|
||||||
match predicate {
|
match predicate {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
WherePredicate::Type(predicate) => {
|
WherePredicate::Type(predicate) => {
|
||||||
self.visit_type_mut(&mut predicate.bounded_ty);
|
self.visit_type_mut(&mut predicate.bounded_ty);
|
||||||
for bound in &mut predicate.bounds {
|
for bound in &mut predicate.bounds {
|
||||||
@@ -235,7 +237,6 @@ impl ReplaceReceiver<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WherePredicate::Lifetime(_) => {}
|
WherePredicate::Lifetime(_) => {}
|
||||||
#[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ pub const FLATTEN: Symbol = Symbol("flatten");
|
|||||||
pub const FROM: Symbol = Symbol("from");
|
pub const FROM: Symbol = Symbol("from");
|
||||||
pub const GETTER: Symbol = Symbol("getter");
|
pub const GETTER: Symbol = Symbol("getter");
|
||||||
pub const INTO: Symbol = Symbol("into");
|
pub const INTO: Symbol = Symbol("into");
|
||||||
|
pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive");
|
||||||
pub const OTHER: Symbol = Symbol("other");
|
pub const OTHER: Symbol = Symbol("other");
|
||||||
pub const REMOTE: Symbol = Symbol("remote");
|
pub const REMOTE: Symbol = Symbol("remote");
|
||||||
pub const RENAME: Symbol = Symbol("rename");
|
pub const RENAME: Symbol = Symbol("rename");
|
||||||
pub const RENAME_ALL: Symbol = Symbol("rename_all");
|
pub const RENAME_ALL: Symbol = Symbol("rename_all");
|
||||||
|
pub const RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields");
|
||||||
pub const REPR: Symbol = Symbol("repr");
|
pub const REPR: Symbol = Symbol("repr");
|
||||||
pub const SERDE: Symbol = Symbol("serde");
|
pub const SERDE: Symbol = Symbol("serde");
|
||||||
pub const SERIALIZE: Symbol = Symbol("serialize");
|
pub const SERIALIZE: Symbol = Symbol("serialize");
|
||||||
@@ -44,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 {
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
*self == word.0
|
*self == word.0
|
||||||
}
|
}
|
||||||
@@ -56,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 {
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
self.is_ident(word.0)
|
self.is_ident(word.0)
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-9
@@ -1,7 +1,7 @@
|
|||||||
//! This crate provides Serde's two derive macros.
|
//! This crate provides Serde's two derive macros.
|
||||||
//!
|
//!
|
||||||
//! ```edition2018
|
//! ```edition2021
|
||||||
//! # use serde_derive::{Serialize, Deserialize};
|
//! # use serde_derive::{Deserialize, Serialize};
|
||||||
//! #
|
//! #
|
||||||
//! #[derive(Serialize, Deserialize)]
|
//! #[derive(Serialize, Deserialize)]
|
||||||
//! # struct S;
|
//! # struct S;
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
//!
|
//!
|
||||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.165")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.228")]
|
||||||
#![allow(unknown_lints, bare_trait_objects)]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
#![allow(
|
#![allow(
|
||||||
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||||
clippy::manual_map,
|
clippy::manual_map,
|
||||||
clippy::match_like_matches_macro,
|
clippy::match_like_matches_macro,
|
||||||
|
clippy::needless_lifetimes,
|
||||||
clippy::needless_pass_by_value,
|
clippy::needless_pass_by_value,
|
||||||
clippy::too_many_arguments,
|
clippy::too_many_arguments,
|
||||||
clippy::trivially_copy_pass_by_ref,
|
clippy::trivially_copy_pass_by_ref,
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
clippy::cast_possible_truncation,
|
clippy::cast_possible_truncation,
|
||||||
clippy::checked_conversions,
|
clippy::checked_conversions,
|
||||||
clippy::doc_markdown,
|
clippy::doc_markdown,
|
||||||
|
clippy::elidable_lifetime_names,
|
||||||
clippy::enum_glob_use,
|
clippy::enum_glob_use,
|
||||||
clippy::indexing_slicing,
|
clippy::indexing_slicing,
|
||||||
clippy::items_after_statements,
|
clippy::items_after_statements,
|
||||||
@@ -51,29 +53,31 @@
|
|||||||
clippy::match_wildcard_for_single_variants,
|
clippy::match_wildcard_for_single_variants,
|
||||||
clippy::module_name_repetitions,
|
clippy::module_name_repetitions,
|
||||||
clippy::must_use_candidate,
|
clippy::must_use_candidate,
|
||||||
clippy::option_if_let_else,
|
|
||||||
clippy::similar_names,
|
clippy::similar_names,
|
||||||
clippy::single_match_else,
|
clippy::single_match_else,
|
||||||
clippy::struct_excessive_bools,
|
clippy::struct_excessive_bools,
|
||||||
clippy::too_many_lines,
|
clippy::too_many_lines,
|
||||||
|
clippy::uninlined_format_args,
|
||||||
clippy::unseparated_literal_suffix,
|
clippy::unseparated_literal_suffix,
|
||||||
clippy::unused_self,
|
clippy::unused_self,
|
||||||
clippy::use_self,
|
clippy::use_self,
|
||||||
clippy::wildcard_imports
|
clippy::wildcard_imports
|
||||||
)]
|
)]
|
||||||
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
|
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
|
||||||
|
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
|
||||||
|
|
||||||
#[macro_use]
|
extern crate proc_macro2;
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate proc_macro2;
|
|
||||||
|
|
||||||
mod internals;
|
mod internals;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
|
use quote::{ToTokens, TokenStreamExt as _};
|
||||||
|
use syn::parse_macro_input;
|
||||||
use syn::DeriveInput;
|
use syn::DeriveInput;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -82,11 +86,29 @@ mod bound;
|
|||||||
mod fragment;
|
mod fragment;
|
||||||
|
|
||||||
mod de;
|
mod de;
|
||||||
|
mod deprecated;
|
||||||
mod dummy;
|
mod dummy;
|
||||||
mod pretend;
|
mod pretend;
|
||||||
mod ser;
|
mod ser;
|
||||||
mod this;
|
mod this;
|
||||||
mod try;
|
|
||||||
|
#[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))]
|
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||||
|
|||||||
+18
-16
@@ -1,7 +1,7 @@
|
|||||||
|
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
|
use crate::private;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::format_ident;
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
use internals::ast::{Container, Data, Field, Style, Variant};
|
|
||||||
|
|
||||||
// Suppress dead_code warnings that would otherwise appear when using a remote
|
// Suppress dead_code warnings that would otherwise appear when using a remote
|
||||||
// derive. Other than this pretend code, a struct annotated with remote derive
|
// derive. Other than this pretend code, a struct annotated with remote derive
|
||||||
@@ -65,14 +65,14 @@ pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
|
|||||||
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
|
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||||
match &cont.data {
|
match &cont.data {
|
||||||
Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
|
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 {
|
if is_packed {
|
||||||
pretend_fields_used_struct_packed(cont, fields)
|
pretend_fields_used_struct_packed(cont, fields)
|
||||||
} else {
|
} else {
|
||||||
pretend_fields_used_struct(cont, fields)
|
pretend_fields_used_struct(cont, fields)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(_, _) => quote!(),
|
Data::Struct(Style::Unit, _) => quote!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream
|
|||||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
match _serde::#private::None::<&#type_ident #ty_generics> {
|
||||||
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
_serde::#private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,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 members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let private2 = private;
|
||||||
quote! {
|
quote! {
|
||||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
match _serde::#private::None::<&#type_ident #ty_generics> {
|
||||||
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
_serde::#private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
||||||
#(
|
#(
|
||||||
let _ = _serde::__private::ptr::addr_of!(__v.#members);
|
let _ = _serde::#private2::ptr::addr_of!(__v.#members);
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -116,20 +117,21 @@ fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStre
|
|||||||
let patterns = variants
|
let patterns = variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| match variant.style {
|
.filter_map(|variant| match variant.style {
|
||||||
Style::Struct => {
|
Style::Struct | Style::Tuple | Style::Newtype => {
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
let members = variant.fields.iter().map(|field| &field.member);
|
let members = variant.fields.iter().map(|field| &field.member);
|
||||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||||
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
|
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
|
||||||
}
|
}
|
||||||
_ => None,
|
Style::Unit => None,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let private2 = private;
|
||||||
quote! {
|
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) => {}
|
||||||
)*
|
)*
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -173,8 +175,8 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
|
|||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
match _serde::__private::None {
|
match _serde::#private::None {
|
||||||
_serde::__private::Some((#(#placeholders,)*)) => {
|
_serde::#private::Some((#(#placeholders,)*)) => {
|
||||||
let _ = #type_ident::#variant_ident #turbofish #pat;
|
let _ = #type_ident::#variant_ident #turbofish #pat;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
+147
-119
@@ -1,20 +1,19 @@
|
|||||||
|
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, private, this};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::{quote, quote_spanned};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{self, Ident, Index, Member};
|
use syn::{parse_quote, Ident, Index, Member};
|
||||||
|
|
||||||
use bound;
|
|
||||||
use dummy;
|
|
||||||
use fragment::{Fragment, Match, Stmts};
|
|
||||||
use internals::ast::{Container, Data, Field, Style, Variant};
|
|
||||||
use internals::{attr, replace_receiver, Ctxt, Derive};
|
|
||||||
use pretend;
|
|
||||||
use this;
|
|
||||||
|
|
||||||
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
|
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
replace_receiver(input);
|
replace_receiver(input);
|
||||||
|
|
||||||
let ctxt = Ctxt::new();
|
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,
|
Some(cont) => cont,
|
||||||
None => return Err(ctxt.check().unwrap_err()),
|
None => return Err(ctxt.check().unwrap_err()),
|
||||||
};
|
};
|
||||||
@@ -25,16 +24,18 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
|||||||
let params = Parameters::new(&cont);
|
let params = Parameters::new(&cont);
|
||||||
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
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 impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||||
let vis = &input.vis;
|
let vis = &input.vis;
|
||||||
let used = pretend::pretend_used(&cont, params.is_packed);
|
let used = pretend::pretend_used(&cont, params.is_packed);
|
||||||
quote! {
|
quote! {
|
||||||
|
#[automatically_derived]
|
||||||
|
#allow_deprecated
|
||||||
impl #impl_generics #ident #ty_generics #where_clause {
|
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
|
where
|
||||||
__S: #serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
#used
|
#used
|
||||||
#body
|
#body
|
||||||
@@ -44,10 +45,11 @@ pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<Toke
|
|||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
#allow_deprecated
|
||||||
fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>
|
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
|
where
|
||||||
__S: #serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
@@ -151,7 +153,7 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
// 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`
|
// 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
|
// 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.
|
// may need a `T: Serialize` bound where T is the type of the field.
|
||||||
@@ -213,7 +215,7 @@ fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
|
|||||||
let self_var = ¶ms.self_var;
|
let self_var = ¶ms.self_var;
|
||||||
quote_block! {
|
quote_block! {
|
||||||
_serde::Serialize::serialize(
|
_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)
|
__serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,16 +287,25 @@ fn serialize_tuple_struct(
|
|||||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len));
|
let #let_mut __serde_state = _serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)?;
|
||||||
#(#serialize_stmts)*
|
#(#serialize_stmts)*
|
||||||
_serde::ser::SerializeTupleStruct::end(__serde_state)
|
_serde::ser::SerializeTupleStruct::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
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)
|
serialize_struct_as_map(params, fields, cattrs)
|
||||||
} else {
|
} else {
|
||||||
serialize_struct_as_struct(params, fields, cattrs)
|
serialize_struct_as_struct(params, fields, cattrs)
|
||||||
@@ -307,7 +318,7 @@ fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTra
|
|||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
let func = struct_trait.serialize_field(Span::call_site());
|
let func = struct_trait.serialize_field(Span::call_site());
|
||||||
quote! {
|
quote! {
|
||||||
try!(#func(&mut __serde_state, #tag, #type_name));
|
#func(&mut __serde_state, #tag, #type_name)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => quote! {},
|
_ => quote! {},
|
||||||
@@ -348,7 +359,7 @@ fn serialize_struct_as_struct(
|
|||||||
);
|
);
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
|
let #let_mut __serde_state = _serde::Serializer::serialize_struct(__serializer, #type_name, #len)?;
|
||||||
#tag_field
|
#tag_field
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStruct::end(__serde_state)
|
_serde::ser::SerializeStruct::end(__serde_state)
|
||||||
@@ -373,26 +384,8 @@ fn serialize_struct_as_map(
|
|||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
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! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::#private::None)?;
|
||||||
#tag_field
|
#tag_field
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
@@ -400,11 +393,11 @@ fn serialize_struct_as_map(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
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;
|
let self_var = ¶ms.self_var;
|
||||||
|
|
||||||
let arms: Vec<_> = variants
|
let mut arms: Vec<_> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(variant_index, variant)| {
|
.map(|(variant_index, variant)| {
|
||||||
@@ -412,6 +405,12 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
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))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
match *#self_var {
|
match *#self_var {
|
||||||
#(#arms)*
|
#(#arms)*
|
||||||
@@ -435,7 +434,7 @@ fn serialize_variant(
|
|||||||
variant_ident
|
variant_ident
|
||||||
);
|
);
|
||||||
let skipped_err = quote! {
|
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 {
|
let fields_pat = match variant.style {
|
||||||
Style::Unit => quote!(),
|
Style::Unit => quote!(),
|
||||||
@@ -481,7 +480,14 @@ fn serialize_variant(
|
|||||||
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
||||||
}
|
}
|
||||||
(attr::TagType::Adjacent { tag, content }, false) => {
|
(attr::TagType::Adjacent { tag, content }, false) => {
|
||||||
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
|
serialize_adjacently_tagged_variant(
|
||||||
|
params,
|
||||||
|
variant,
|
||||||
|
cattrs,
|
||||||
|
variant_index,
|
||||||
|
tag,
|
||||||
|
content,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(attr::TagType::None, _) | (_, true) => {
|
(attr::TagType::None, _) | (_, true) => {
|
||||||
serialize_untagged_variant(params, variant, cattrs)
|
serialize_untagged_variant(params, variant, cattrs)
|
||||||
@@ -562,7 +568,7 @@ fn serialize_externally_tagged_variant(
|
|||||||
},
|
},
|
||||||
params,
|
params,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
&type_name,
|
type_name,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -582,7 +588,7 @@ fn serialize_internally_tagged_variant(
|
|||||||
if let Some(path) = variant.attrs.serialize_with() {
|
if let Some(path) = variant.attrs.serialize_with() {
|
||||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||||
return quote_expr! {
|
return quote_expr! {
|
||||||
_serde::__private::ser::serialize_tagged_newtype(
|
_serde::#private::ser::serialize_tagged_newtype(
|
||||||
__serializer,
|
__serializer,
|
||||||
#enum_ident_str,
|
#enum_ident_str,
|
||||||
#variant_ident_str,
|
#variant_ident_str,
|
||||||
@@ -596,10 +602,10 @@ fn serialize_internally_tagged_variant(
|
|||||||
match effective_style(variant) {
|
match effective_style(variant) {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
let mut __struct = _serde::Serializer::serialize_struct(
|
||||||
__serializer, #type_name, 1));
|
__serializer, #type_name, 1)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #tag, #variant_name));
|
&mut __struct, #tag, #variant_name)?;
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,7 +617,7 @@ fn serialize_internally_tagged_variant(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let span = field.original.span();
|
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! {
|
quote_expr! {
|
||||||
#func(
|
#func(
|
||||||
__serializer,
|
__serializer,
|
||||||
@@ -627,7 +633,7 @@ fn serialize_internally_tagged_variant(
|
|||||||
StructVariant::InternallyTagged { tag, variant_name },
|
StructVariant::InternallyTagged { tag, variant_name },
|
||||||
params,
|
params,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
&type_name,
|
type_name,
|
||||||
),
|
),
|
||||||
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
Style::Tuple => unreachable!("checked in serde_derive_internals"),
|
||||||
}
|
}
|
||||||
@@ -637,12 +643,20 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
|
variant_index: u32,
|
||||||
tag: &str,
|
tag: &str,
|
||||||
content: &str,
|
content: &str,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let this_type = ¶ms.this_type;
|
let this_type = ¶ms.this_type;
|
||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
let variant_name = variant.attrs.name().serialize_name();
|
let variant_name = variant.attrs.name().serialize_name();
|
||||||
|
let serialize_variant = quote! {
|
||||||
|
&_serde::#private::ser::AdjacentlyTaggedEnumVariant {
|
||||||
|
enum_name: #type_name,
|
||||||
|
variant_index: #variant_index,
|
||||||
|
variant_name: #variant_name,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
|
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
|
||||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||||
@@ -653,10 +667,10 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
match effective_style(variant) {
|
match effective_style(variant) {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
return quote_block! {
|
return quote_block! {
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
let mut __struct = _serde::Serializer::serialize_struct(
|
||||||
__serializer, #type_name, 1));
|
__serializer, #type_name, 1)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #tag, #variant_name));
|
&mut __struct, #tag, #serialize_variant)?;
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -670,12 +684,12 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
let span = field.original.span();
|
let span = field.original.span();
|
||||||
let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field);
|
let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field);
|
||||||
return quote_block! {
|
return quote_block! {
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
let mut __struct = _serde::Serializer::serialize_struct(
|
||||||
__serializer, #type_name, 2));
|
__serializer, #type_name, 2)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #tag, #variant_name));
|
&mut __struct, #tag, #serialize_variant)?;
|
||||||
try!(#func(
|
#func(
|
||||||
&mut __struct, #content, #field_expr));
|
&mut __struct, #content, #field_expr)?;
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -686,13 +700,13 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
StructVariant::Untagged,
|
StructVariant::Untagged,
|
||||||
params,
|
params,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
&variant_name,
|
variant_name,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||||
let fields_ident: &Vec<_> = &match variant.style {
|
let fields_ident: &[_] = &match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
if variant.attrs.serialize_with().is_some() {
|
if variant.attrs.serialize_with().is_some() {
|
||||||
vec![]
|
vec![]
|
||||||
@@ -720,11 +734,12 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
||||||
data: (#(&'__a #fields_ty,)*),
|
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 {
|
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
|
where
|
||||||
__S: _serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
@@ -735,15 +750,15 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
let mut __struct = _serde::Serializer::serialize_struct(
|
||||||
__serializer, #type_name, 2));
|
__serializer, #type_name, 2)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #tag, #variant_name));
|
&mut __struct, #tag, #serialize_variant)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #content, &__AdjacentlyTagged {
|
&mut __struct, #content, &__AdjacentlyTagged {
|
||||||
data: (#(#fields_ident,)*),
|
data: (#(#fields_ident,)*),
|
||||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||||
}));
|
})?;
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -782,16 +797,16 @@ fn serialize_untagged_variant(
|
|||||||
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
|
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
|
||||||
Style::Struct => {
|
Style::Struct => {
|
||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, &type_name)
|
serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, type_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TupleVariant {
|
enum TupleVariant<'a> {
|
||||||
ExternallyTagged {
|
ExternallyTagged {
|
||||||
type_name: String,
|
type_name: &'a Name,
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant_name: String,
|
variant_name: &'a Name,
|
||||||
},
|
},
|
||||||
Untagged,
|
Untagged,
|
||||||
}
|
}
|
||||||
@@ -833,21 +848,21 @@ fn serialize_tuple_variant(
|
|||||||
variant_name,
|
variant_name,
|
||||||
} => {
|
} => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant(
|
let #let_mut __serde_state = _serde::Serializer::serialize_tuple_variant(
|
||||||
__serializer,
|
__serializer,
|
||||||
#type_name,
|
#type_name,
|
||||||
#variant_index,
|
#variant_index,
|
||||||
#variant_name,
|
#variant_name,
|
||||||
#len));
|
#len)?;
|
||||||
#(#serialize_stmts)*
|
#(#serialize_stmts)*
|
||||||
_serde::ser::SerializeTupleVariant::end(__serde_state)
|
_serde::ser::SerializeTupleVariant::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TupleVariant::Untagged => {
|
TupleVariant::Untagged => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple(
|
let #let_mut __serde_state = _serde::Serializer::serialize_tuple(
|
||||||
__serializer,
|
__serializer,
|
||||||
#len));
|
#len)?;
|
||||||
#(#serialize_stmts)*
|
#(#serialize_stmts)*
|
||||||
_serde::ser::SerializeTuple::end(__serde_state)
|
_serde::ser::SerializeTuple::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -858,11 +873,11 @@ fn serialize_tuple_variant(
|
|||||||
enum StructVariant<'a> {
|
enum StructVariant<'a> {
|
||||||
ExternallyTagged {
|
ExternallyTagged {
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant_name: String,
|
variant_name: &'a Name,
|
||||||
},
|
},
|
||||||
InternallyTagged {
|
InternallyTagged {
|
||||||
tag: &'a str,
|
tag: &'a str,
|
||||||
variant_name: String,
|
variant_name: &'a Name,
|
||||||
},
|
},
|
||||||
Untagged,
|
Untagged,
|
||||||
}
|
}
|
||||||
@@ -871,7 +886,7 @@ fn serialize_struct_variant(
|
|||||||
context: StructVariant,
|
context: StructVariant,
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
name: &str,
|
name: &Name,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
if fields.iter().any(|field| field.attrs.flatten()) {
|
if fields.iter().any(|field| field.attrs.flatten()) {
|
||||||
return serialize_struct_variant_with_flatten(context, params, fields, name);
|
return serialize_struct_variant_with_flatten(context, params, fields, name);
|
||||||
@@ -910,40 +925,40 @@ fn serialize_struct_variant(
|
|||||||
variant_name,
|
variant_name,
|
||||||
} => {
|
} => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant(
|
let #let_mut __serde_state = _serde::Serializer::serialize_struct_variant(
|
||||||
__serializer,
|
__serializer,
|
||||||
#name,
|
#name,
|
||||||
#variant_index,
|
#variant_index,
|
||||||
#variant_name,
|
#variant_name,
|
||||||
#len,
|
#len,
|
||||||
));
|
)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStructVariant::end(__serde_state)
|
_serde::ser::SerializeStructVariant::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructVariant::InternallyTagged { tag, variant_name } => {
|
StructVariant::InternallyTagged { tag, variant_name } => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
let mut __serde_state = _serde::Serializer::serialize_struct(
|
||||||
__serializer,
|
__serializer,
|
||||||
#name,
|
#name,
|
||||||
#len + 1,
|
#len + 1,
|
||||||
));
|
)?;
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __serde_state,
|
&mut __serde_state,
|
||||||
#tag,
|
#tag,
|
||||||
#variant_name,
|
#variant_name,
|
||||||
));
|
)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStruct::end(__serde_state)
|
_serde::ser::SerializeStruct::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructVariant::Untagged => {
|
StructVariant::Untagged => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
let #let_mut __serde_state = _serde::Serializer::serialize_struct(
|
||||||
__serializer,
|
__serializer,
|
||||||
#name,
|
#name,
|
||||||
#len,
|
#len,
|
||||||
));
|
)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStruct::end(__serde_state)
|
_serde::ser::SerializeStruct::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -955,7 +970,7 @@ fn serialize_struct_variant_with_flatten(
|
|||||||
context: StructVariant,
|
context: StructVariant,
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
name: &str,
|
name: &Name,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let struct_trait = StructTrait::SerializeMap;
|
let struct_trait = StructTrait::SerializeMap;
|
||||||
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
|
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
|
||||||
@@ -984,18 +999,19 @@ fn serialize_struct_variant_with_flatten(
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
struct __EnumFlatten #wrapper_generics #where_clause {
|
struct __EnumFlatten #wrapper_generics #where_clause {
|
||||||
data: (#(&'__a #fields_ty,)*),
|
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 {
|
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
|
where
|
||||||
__S: _serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
let (#(#members,)*) = self.data;
|
let (#(#members,)*) = self.data;
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||||
__serializer,
|
__serializer,
|
||||||
_serde::__private::None));
|
_serde::#private::None)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -1008,29 +1024,29 @@ fn serialize_struct_variant_with_flatten(
|
|||||||
#variant_name,
|
#variant_name,
|
||||||
&__EnumFlatten {
|
&__EnumFlatten {
|
||||||
data: (#(#members,)*),
|
data: (#(#members,)*),
|
||||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructVariant::InternallyTagged { tag, variant_name } => {
|
StructVariant::InternallyTagged { tag, variant_name } => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||||
__serializer,
|
__serializer,
|
||||||
_serde::__private::None));
|
_serde::#private::None)?;
|
||||||
try!(_serde::ser::SerializeMap::serialize_entry(
|
_serde::ser::SerializeMap::serialize_entry(
|
||||||
&mut __serde_state,
|
&mut __serde_state,
|
||||||
#tag,
|
#tag,
|
||||||
#variant_name,
|
#variant_name,
|
||||||
));
|
)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructVariant::Untagged => {
|
StructVariant::Untagged => {
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
let #let_mut __serde_state = _serde::Serializer::serialize_map(
|
||||||
__serializer,
|
__serializer,
|
||||||
_serde::__private::None));
|
_serde::#private::None)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -1075,7 +1091,7 @@ fn serialize_tuple_struct_visitor(
|
|||||||
let span = field.original.span();
|
let span = field.original.span();
|
||||||
let func = tuple_trait.serialize_element(span);
|
let func = tuple_trait.serialize_element(span);
|
||||||
let ser = quote! {
|
let ser = quote! {
|
||||||
try!(#func(&mut __serde_state, #field_expr));
|
#func(&mut __serde_state, #field_expr)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
match skip {
|
match skip {
|
||||||
@@ -1119,12 +1135,12 @@ fn serialize_struct_visitor(
|
|||||||
let ser = if field.attrs.flatten() {
|
let ser = if field.attrs.flatten() {
|
||||||
let func = quote_spanned!(span=> _serde::Serialize::serialize);
|
let func = quote_spanned!(span=> _serde::Serialize::serialize);
|
||||||
quote! {
|
quote! {
|
||||||
try!(#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state)));
|
#func(&#field_expr, _serde::#private::ser::FlatMapSerializer(&mut __serde_state))?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let func = struct_trait.serialize_field(span);
|
let func = struct_trait.serialize_field(span);
|
||||||
quote! {
|
quote! {
|
||||||
try!(#func(&mut __serde_state, #key_expr, #field_expr));
|
#func(&mut __serde_state, #key_expr, #field_expr)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1136,7 +1152,7 @@ fn serialize_struct_visitor(
|
|||||||
if !#skip {
|
if !#skip {
|
||||||
#ser
|
#ser
|
||||||
} else {
|
} else {
|
||||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
#skip_func(&mut __serde_state, #key_expr)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1211,32 +1227,44 @@ 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)]
|
#[doc(hidden)]
|
||||||
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
struct __SerializeWith #wrapper_impl_generics #where_clause {
|
||||||
values: (#(&'__a #field_tys, )*),
|
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 {
|
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
|
where
|
||||||
__S: _serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
#serialize_with(#(self.values.#field_access, )* __s)
|
#wrapper_serialize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__SerializeWith {
|
__SerializeWith {
|
||||||
values: (#(#field_exprs, )*),
|
values: (#(#field_exprs, )*),
|
||||||
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
phantom: _serde::#private::PhantomData::<#this_type #ty_generics>,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialization of an empty struct results in code like:
|
// Serialization of an empty struct results in code like:
|
||||||
//
|
//
|
||||||
// let mut __serde_state = try!(serializer.serialize_struct("S", 0));
|
// let mut __serde_state = serializer.serialize_struct("S", 0)?;
|
||||||
// _serde::ser::SerializeStruct::end(__serde_state)
|
// _serde::ser::SerializeStruct::end(__serde_state)
|
||||||
//
|
//
|
||||||
// where we want to omit the `mut` to avoid a warning.
|
// where we want to omit the `mut` to avoid a warning.
|
||||||
@@ -1265,11 +1293,11 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea
|
|||||||
quote!(&#self_var.#member)
|
quote!(&#self_var.#member)
|
||||||
};
|
};
|
||||||
let ty = field.ty;
|
let ty = field.ty;
|
||||||
quote!(_serde::__private::ser::constrain::<#ty>(#inner))
|
quote!(_serde::#private::ser::constrain::<#ty>(#inner))
|
||||||
}
|
}
|
||||||
(true, Some(getter)) => {
|
(true, Some(getter)) => {
|
||||||
let ty = field.ty;
|
let ty = field.ty;
|
||||||
quote!(_serde::__private::ser::constrain::<#ty>(&#getter(#self_var)))
|
quote!(_serde::#private::ser::constrain::<#ty>(&#getter(#self_var)))
|
||||||
}
|
}
|
||||||
(false, Some(_)) => {
|
(false, Some(_)) => {
|
||||||
unreachable!("getter is only allowed for remote impls");
|
unreachable!("getter is only allowed for remote impls");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use internals::ast::Container;
|
use crate::internals::ast::Container;
|
||||||
use syn::{Path, PathArguments, Token};
|
use syn::{Path, PathArguments, Token};
|
||||||
|
|
||||||
pub fn this_type(cont: &Container) -> Path {
|
pub fn this_type(cont: &Container) -> Path {
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
use proc_macro2::{Punct, Spacing, TokenStream};
|
|
||||||
|
|
||||||
// None of our generated code requires the `From::from` error conversion
|
|
||||||
// performed by the standard library's `try!` macro. With this simplified macro
|
|
||||||
// we see a significant improvement in type checking and borrow checking time of
|
|
||||||
// the generated code and a slight improvement in binary size.
|
|
||||||
pub fn replacement() -> TokenStream {
|
|
||||||
// Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it.
|
|
||||||
let dollar = Punct::new('$', Spacing::Alone);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#[allow(unused_macros)]
|
|
||||||
macro_rules! try {
|
|
||||||
(#dollar __expr:expr) => {
|
|
||||||
match #dollar __expr {
|
|
||||||
_serde::__private::Ok(__val) => __val,
|
|
||||||
_serde::__private::Err(__err) => {
|
|
||||||
return _serde::__private::Err(__err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,32 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive_internals"
|
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>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
description = "AST representation used by Serde derive macros. Unstable."
|
description = "AST representation used by Serde derive macros. Unstable."
|
||||||
documentation = "https://docs.rs/serde_derive_internals"
|
documentation = "https://docs.rs/serde_derive_internals"
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["build.rs"]
|
||||||
homepage = "https://serde.rs"
|
homepage = "https://serde.rs"
|
||||||
include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
keywords = ["serde", "serialization"]
|
keywords = ["serde", "serialization"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/serde-rs/serde"
|
repository = "https://github.com/serde-rs/serde"
|
||||||
rust-version = "1.56"
|
rust-version = "1.61"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = { workspace = true }
|
||||||
quote = "1.0"
|
quote = { workspace = true }
|
||||||
syn = { version = "2.0.21", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
|
syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing"] }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
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",
|
||||||
|
"--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// Warning: build.rs is not published to crates.io.
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
println!("cargo:rerun-if-changed=src/mod.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
|
// Sometimes on Windows the git checkout does not correctly wire up the
|
||||||
// symlink from serde_derive_internals/src to serde_derive/src/internals.
|
// 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
|
// When this happens we'll just build based on relative paths within the git
|
||||||
|
|||||||
@@ -1,5 +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")]
|
||||||
#![allow(unknown_lints, bare_trait_objects)]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::cognitive_complexity,
|
clippy::cognitive_complexity,
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||||
clippy::manual_map,
|
clippy::manual_map,
|
||||||
clippy::missing_panics_doc,
|
clippy::missing_panics_doc,
|
||||||
|
clippy::needless_lifetimes,
|
||||||
clippy::redundant_field_names,
|
clippy::redundant_field_names,
|
||||||
clippy::result_unit_err,
|
clippy::result_unit_err,
|
||||||
clippy::should_implement_trait,
|
clippy::should_implement_trait,
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
// Ignored clippy_pedantic lints
|
// Ignored clippy_pedantic lints
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::doc_markdown,
|
clippy::doc_markdown,
|
||||||
|
clippy::elidable_lifetime_names,
|
||||||
clippy::enum_glob_use,
|
clippy::enum_glob_use,
|
||||||
clippy::items_after_statements,
|
clippy::items_after_statements,
|
||||||
clippy::let_underscore_untyped,
|
clippy::let_underscore_untyped,
|
||||||
@@ -30,19 +32,20 @@
|
|||||||
clippy::missing_errors_doc,
|
clippy::missing_errors_doc,
|
||||||
clippy::module_name_repetitions,
|
clippy::module_name_repetitions,
|
||||||
clippy::must_use_candidate,
|
clippy::must_use_candidate,
|
||||||
|
clippy::return_self_not_must_use,
|
||||||
clippy::similar_names,
|
clippy::similar_names,
|
||||||
clippy::single_match_else,
|
clippy::single_match_else,
|
||||||
clippy::struct_excessive_bools,
|
clippy::struct_excessive_bools,
|
||||||
clippy::too_many_lines,
|
clippy::too_many_lines,
|
||||||
|
clippy::uninlined_format_args,
|
||||||
clippy::unused_self,
|
clippy::unused_self,
|
||||||
clippy::wildcard_imports
|
clippy::wildcard_imports
|
||||||
)]
|
)]
|
||||||
|
#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
|
||||||
|
|
||||||
extern crate proc_macro2;
|
extern crate proc_macro2;
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
|
extern crate syn;
|
||||||
|
|
||||||
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
|
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
|
||||||
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
|
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "serde_test"
|
|
||||||
version = "1.0.165" # remember to update html_root_url
|
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
|
||||||
build = "build.rs"
|
|
||||||
categories = ["development-tools::testing"]
|
|
||||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
|
||||||
documentation = "https://docs.rs/serde_test"
|
|
||||||
homepage = "https://serde.rs"
|
|
||||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
keywords = ["serde", "serialization", "testing", "dev-dependencies"]
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
readme = "crates-io.md"
|
|
||||||
repository = "https://github.com/serde-rs/serde"
|
|
||||||
rust-version = "1.19"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde = { version = "1.0.60", path = "../serde" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
serde = { version = "1.0", path = "../serde" }
|
|
||||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
targets = ["x86_64-unknown-linux-gnu"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../README.md
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
use std::env;
|
|
||||||
use std::process::Command;
|
|
||||||
use std::str::{self, FromStr};
|
|
||||||
|
|
||||||
// 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 minor = match rustc_minor_version() {
|
|
||||||
Some(minor) => minor,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
// #[track_caller] stabilized in Rust 1.46:
|
|
||||||
// https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
|
|
||||||
if minor < 46 {
|
|
||||||
println!("cargo:rustc-cfg=no_track_caller");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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()
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../crates-io.md
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use de::Deserializer;
|
|
||||||
use ser::Serializer;
|
|
||||||
use token::Token;
|
|
||||||
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct S {
|
|
||||||
/// a: u8,
|
|
||||||
/// b: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let s = S { a: 0, b: 0 };
|
|
||||||
/// assert_tokens(&s, &[
|
|
||||||
/// Token::Struct { name: "S", len: 2 },
|
|
||||||
/// Token::Str("a"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::Str("b"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::StructEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(not(no_track_caller), track_caller)]
|
|
||||||
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
|
||||||
where
|
|
||||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
|
||||||
{
|
|
||||||
assert_ser_tokens(value, tokens);
|
|
||||||
assert_de_tokens(value, tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asserts that `value` serializes to the given `tokens`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_ser_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct S {
|
|
||||||
/// a: u8,
|
|
||||||
/// b: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let s = S { a: 0, b: 0 };
|
|
||||||
/// assert_ser_tokens(&s, &[
|
|
||||||
/// Token::Struct { name: "S", len: 2 },
|
|
||||||
/// Token::Str("a"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::Str("b"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::StructEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(not(no_track_caller), track_caller)]
|
|
||||||
pub fn assert_ser_tokens<T: ?Sized>(value: &T, tokens: &[Token])
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
let mut ser = Serializer::new(tokens);
|
|
||||||
match value.serialize(&mut ser) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(err) => panic!("value failed to serialize: {}", err),
|
|
||||||
}
|
|
||||||
|
|
||||||
if ser.remaining() > 0 {
|
|
||||||
panic!("{} remaining tokens", ser.remaining());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asserts that `value` serializes to the given `tokens`, and then yields
|
|
||||||
/// `error`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// use std::sync::{Arc, Mutex};
|
|
||||||
/// use std::thread;
|
|
||||||
///
|
|
||||||
/// use serde::Serialize;
|
|
||||||
/// use serde_test::{assert_ser_tokens_error, Token};
|
|
||||||
///
|
|
||||||
/// #[derive(Serialize)]
|
|
||||||
/// struct Example {
|
|
||||||
/// lock: Arc<Mutex<u32>>,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
|
|
||||||
/// let lock = example.lock.clone();
|
|
||||||
///
|
|
||||||
/// let _ = thread::spawn(move || {
|
|
||||||
/// // This thread will acquire the mutex first, unwrapping the result
|
|
||||||
/// // of `lock` because the lock has not been poisoned.
|
|
||||||
/// let _guard = lock.lock().unwrap();
|
|
||||||
///
|
|
||||||
/// // This panic while holding the lock (`_guard` is in scope) will
|
|
||||||
/// // poison the mutex.
|
|
||||||
/// panic!()
|
|
||||||
/// }).join();
|
|
||||||
///
|
|
||||||
/// let expected = &[
|
|
||||||
/// Token::Struct { name: "Example", len: 1 },
|
|
||||||
/// Token::Str("lock"),
|
|
||||||
/// ];
|
|
||||||
/// let error = "lock poison error while serializing";
|
|
||||||
/// assert_ser_tokens_error(&example, expected, error);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(not(no_track_caller), track_caller)]
|
|
||||||
pub fn assert_ser_tokens_error<T: ?Sized>(value: &T, tokens: &[Token], error: &str)
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
let mut ser = Serializer::new(tokens);
|
|
||||||
match value.serialize(&mut ser) {
|
|
||||||
Ok(_) => panic!("value serialized successfully"),
|
|
||||||
Err(e) => assert_eq!(e, *error),
|
|
||||||
}
|
|
||||||
|
|
||||||
if ser.remaining() > 0 {
|
|
||||||
panic!("{} remaining tokens", ser.remaining());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asserts that the given `tokens` deserialize into `value`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_de_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct S {
|
|
||||||
/// a: u8,
|
|
||||||
/// b: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let s = S { a: 0, b: 0 };
|
|
||||||
/// assert_de_tokens(&s, &[
|
|
||||||
/// Token::Struct { name: "S", len: 2 },
|
|
||||||
/// Token::Str("a"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::Str("b"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::StructEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(not(no_track_caller), track_caller)]
|
|
||||||
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
|
||||||
where
|
|
||||||
T: Deserialize<'de> + PartialEq + Debug,
|
|
||||||
{
|
|
||||||
let mut de = Deserializer::new(tokens);
|
|
||||||
let mut deserialized_val = match T::deserialize(&mut de) {
|
|
||||||
Ok(v) => {
|
|
||||||
assert_eq!(v, *value);
|
|
||||||
v
|
|
||||||
}
|
|
||||||
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
|
||||||
};
|
|
||||||
if de.remaining() > 0 {
|
|
||||||
panic!("{} remaining tokens", de.remaining());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the same thing for deserialize_in_place. This isn't *great* because a
|
|
||||||
// no-op impl of deserialize_in_place can technically succeed here. Still,
|
|
||||||
// this should catch a lot of junk.
|
|
||||||
let mut de = Deserializer::new(tokens);
|
|
||||||
match T::deserialize_in_place(&mut de, &mut deserialized_val) {
|
|
||||||
Ok(()) => {
|
|
||||||
assert_eq!(deserialized_val, *value);
|
|
||||||
}
|
|
||||||
Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
|
|
||||||
}
|
|
||||||
if de.remaining() > 0 {
|
|
||||||
panic!("{} remaining tokens", de.remaining());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asserts that the given `tokens` yield `error` when deserializing.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_de_tokens_error, Token};
|
|
||||||
/// #
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// #[serde(deny_unknown_fields)]
|
|
||||||
/// struct S {
|
|
||||||
/// a: u8,
|
|
||||||
/// b: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// assert_de_tokens_error::<S>(
|
|
||||||
/// &[
|
|
||||||
/// Token::Struct { name: "S", len: 2 },
|
|
||||||
/// Token::Str("x"),
|
|
||||||
/// ],
|
|
||||||
/// "unknown field `x`, expected `a` or `b`",
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(not(no_track_caller), track_caller)]
|
|
||||||
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
|
|
||||||
where
|
|
||||||
T: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
let mut de = Deserializer::new(tokens);
|
|
||||||
match T::deserialize(&mut de) {
|
|
||||||
Ok(_) => panic!("tokens deserialized successfully"),
|
|
||||||
Err(e) => assert_eq!(e, *error),
|
|
||||||
}
|
|
||||||
|
|
||||||
// There may be one token left if a peek caused the error
|
|
||||||
de.next_token_opt();
|
|
||||||
|
|
||||||
if de.remaining() > 0 {
|
|
||||||
panic!("{} remaining tokens", de.remaining());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,847 +0,0 @@
|
|||||||
use std::fmt;
|
|
||||||
|
|
||||||
use serde::ser::{
|
|
||||||
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
|
|
||||||
SerializeTupleStruct, SerializeTupleVariant,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Readable<T: ?Sized>(T);
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct Compact<T: ?Sized>(T);
|
|
||||||
|
|
||||||
/// Trait to determine whether a value is represented in human-readable or
|
|
||||||
/// compact form.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
/// use serde_test::{assert_tokens, Configure, Token};
|
|
||||||
///
|
|
||||||
/// #[derive(Debug, PartialEq)]
|
|
||||||
/// struct Example(u8, u8);
|
|
||||||
///
|
|
||||||
/// impl Serialize for Example {
|
|
||||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
/// where
|
|
||||||
/// S: Serializer,
|
|
||||||
/// {
|
|
||||||
/// if serializer.is_human_readable() {
|
|
||||||
/// format!("{}.{}", self.0, self.1).serialize(serializer)
|
|
||||||
/// } else {
|
|
||||||
/// (self.0, self.1).serialize(serializer)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl<'de> Deserialize<'de> for Example {
|
|
||||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
/// where
|
|
||||||
/// D: Deserializer<'de>,
|
|
||||||
/// {
|
|
||||||
/// use serde::de::Error;
|
|
||||||
/// if deserializer.is_human_readable() {
|
|
||||||
/// let s = String::deserialize(deserializer)?;
|
|
||||||
/// let parts: Vec<_> = s.split('.').collect();
|
|
||||||
/// Ok(Example(
|
|
||||||
/// parts[0].parse().map_err(D::Error::custom)?,
|
|
||||||
/// parts[1].parse().map_err(D::Error::custom)?,
|
|
||||||
/// ))
|
|
||||||
/// } else {
|
|
||||||
/// let (x, y) = Deserialize::deserialize(deserializer)?;
|
|
||||||
/// Ok(Example(x, y))
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn main() {
|
|
||||||
/// assert_tokens(
|
|
||||||
/// &Example(1, 0).compact(),
|
|
||||||
/// &[
|
|
||||||
/// Token::Tuple { len: 2 },
|
|
||||||
/// Token::U8(1),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::TupleEnd,
|
|
||||||
/// ],
|
|
||||||
/// );
|
|
||||||
/// assert_tokens(&Example(1, 0).readable(), &[Token::Str("1.0")]);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub trait Configure {
|
|
||||||
/// Marks `self` as using `is_human_readable == true`
|
|
||||||
fn readable(self) -> Readable<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Readable(self)
|
|
||||||
}
|
|
||||||
/// Marks `self` as using `is_human_readable == false`
|
|
||||||
fn compact(self) -> Compact<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
Compact(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ?Sized> Configure for T {}
|
|
||||||
|
|
||||||
impl<T: ?Sized> Serialize for Readable<T>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
self.0.serialize(Readable(serializer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: ?Sized> Serialize for Compact<T>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
self.0.serialize(Compact(serializer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'de, T> Deserialize<'de> for Readable<T>
|
|
||||||
where
|
|
||||||
T: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
T::deserialize(Readable(deserializer)).map(Readable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'de, T> Deserialize<'de> for Compact<T>
|
|
||||||
where
|
|
||||||
T: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
T::deserialize(Compact(deserializer)).map(Compact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, T> DeserializeSeed<'de> for Readable<T>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
type Value = T::Value;
|
|
||||||
|
|
||||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize(Readable(deserializer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'de, T> DeserializeSeed<'de> for Compact<T>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
type Value = T::Value;
|
|
||||||
|
|
||||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize(Compact(deserializer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_method {
|
|
||||||
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
|
|
||||||
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
|
|
||||||
(self.0).$name( $($arg),* )
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! forward_serialize_methods {
|
|
||||||
( $( $name: ident $arg_type: ty ),* ) => {
|
|
||||||
$(
|
|
||||||
forward_method!($name(self, v : $arg_type) -> Result<Self::Ok, Self::Error>);
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_serializer {
|
|
||||||
($wrapper:ident, $is_human_readable:expr) => {
|
|
||||||
impl<S> Serializer for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
|
|
||||||
type SerializeSeq = $wrapper<S::SerializeSeq>;
|
|
||||||
type SerializeTuple = $wrapper<S::SerializeTuple>;
|
|
||||||
type SerializeTupleStruct = $wrapper<S::SerializeTupleStruct>;
|
|
||||||
type SerializeTupleVariant = $wrapper<S::SerializeTupleVariant>;
|
|
||||||
type SerializeMap = $wrapper<S::SerializeMap>;
|
|
||||||
type SerializeStruct = $wrapper<S::SerializeStruct>;
|
|
||||||
type SerializeStructVariant = $wrapper<S::SerializeStructVariant>;
|
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
|
||||||
$is_human_readable
|
|
||||||
}
|
|
||||||
|
|
||||||
forward_serialize_methods! {
|
|
||||||
serialize_bool bool,
|
|
||||||
serialize_i8 i8,
|
|
||||||
serialize_i16 i16,
|
|
||||||
serialize_i32 i32,
|
|
||||||
serialize_i64 i64,
|
|
||||||
serialize_u8 u8,
|
|
||||||
serialize_u16 u16,
|
|
||||||
serialize_u32 u32,
|
|
||||||
serialize_u64 u64,
|
|
||||||
serialize_f32 f32,
|
|
||||||
serialize_f64 f64,
|
|
||||||
serialize_char char,
|
|
||||||
serialize_str &str,
|
|
||||||
serialize_bytes &[u8],
|
|
||||||
serialize_unit_struct &'static str
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.serialize_unit()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.serialize_unit_variant(name, variant_index, variant)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_newtype_struct<T: ?Sized>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_newtype_struct(name, &$wrapper(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0
|
|
||||||
.serialize_newtype_variant(name, variant_index, variant, &$wrapper(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<S::Ok, Self::Error> {
|
|
||||||
self.0.serialize_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<S::Ok, Self::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_some(&$wrapper(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
|
||||||
self.0.serialize_seq(len).map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
|
||||||
self.0.serialize_tuple(len).map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple_struct(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
|
||||||
self.0.serialize_tuple_struct(name, len).map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
|
||||||
self.0
|
|
||||||
.serialize_tuple_variant(name, variant_index, variant, len)
|
|
||||||
.map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
|
||||||
self.0.serialize_map(len).map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_struct(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
|
||||||
self.0.serialize_struct(name, len).map($wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_struct_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
|
||||||
self.0
|
|
||||||
.serialize_struct_variant(name, variant_index, variant, len)
|
|
||||||
.map($wrapper)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeSeq for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeSeq,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_element(&$wrapper(value))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeTuple for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeTuple,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_element(&$wrapper(value))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeTupleStruct for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeTupleStruct,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_field(&$wrapper(value))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeTupleVariant for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeTupleVariant,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_field(&$wrapper(value))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeMap for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeMap,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_key(&$wrapper(key))
|
|
||||||
}
|
|
||||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_value(&$wrapper(value))
|
|
||||||
}
|
|
||||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
|
||||||
&mut self,
|
|
||||||
key: &K,
|
|
||||||
value: &V,
|
|
||||||
) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
K: Serialize,
|
|
||||||
V: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_entry(key, &$wrapper(value))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeStruct for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeStruct,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_field<T: ?Sized>(
|
|
||||||
&mut self,
|
|
||||||
name: &'static str,
|
|
||||||
field: &T,
|
|
||||||
) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_field(name, &$wrapper(field))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> SerializeStructVariant for $wrapper<S>
|
|
||||||
where
|
|
||||||
S: SerializeStructVariant,
|
|
||||||
{
|
|
||||||
type Ok = S::Ok;
|
|
||||||
type Error = S::Error;
|
|
||||||
fn serialize_field<T: ?Sized>(
|
|
||||||
&mut self,
|
|
||||||
name: &'static str,
|
|
||||||
field: &T,
|
|
||||||
) -> Result<(), S::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
self.0.serialize_field(name, &$wrapper(field))
|
|
||||||
}
|
|
||||||
fn end(self) -> Result<S::Ok, S::Error> {
|
|
||||||
self.0.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_serializer!(Readable, true);
|
|
||||||
impl_serializer!(Compact, false);
|
|
||||||
|
|
||||||
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
|
|
||||||
|
|
||||||
macro_rules! forward_deserialize_methods {
|
|
||||||
( $wrapper : ident ( $( $name: ident ),* ) ) => {
|
|
||||||
$(
|
|
||||||
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
(self.0).$name($wrapper(visitor))
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_deserializer {
|
|
||||||
($wrapper:ident, $is_human_readable:expr) => {
|
|
||||||
impl<'de, D> Deserializer<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
type Error = D::Error;
|
|
||||||
|
|
||||||
forward_deserialize_methods! {
|
|
||||||
$wrapper (
|
|
||||||
deserialize_any,
|
|
||||||
deserialize_bool,
|
|
||||||
deserialize_u8,
|
|
||||||
deserialize_u16,
|
|
||||||
deserialize_u32,
|
|
||||||
deserialize_u64,
|
|
||||||
deserialize_i8,
|
|
||||||
deserialize_i16,
|
|
||||||
deserialize_i32,
|
|
||||||
deserialize_i64,
|
|
||||||
deserialize_f32,
|
|
||||||
deserialize_f64,
|
|
||||||
deserialize_char,
|
|
||||||
deserialize_str,
|
|
||||||
deserialize_string,
|
|
||||||
deserialize_bytes,
|
|
||||||
deserialize_byte_buf,
|
|
||||||
deserialize_option,
|
|
||||||
deserialize_unit,
|
|
||||||
deserialize_seq,
|
|
||||||
deserialize_map,
|
|
||||||
deserialize_identifier,
|
|
||||||
deserialize_ignored_any
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize_unit_struct(name, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn deserialize_newtype_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize_newtype_struct(name, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize_tuple(len, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn deserialize_tuple_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
len: usize,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0
|
|
||||||
.deserialize_tuple_struct(name, len, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn deserialize_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
fields: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize_struct(name, fields, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn deserialize_enum<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
variants: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.deserialize_enum(name, variants, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
|
||||||
$is_human_readable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, D> Visitor<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: Visitor<'de>,
|
|
||||||
{
|
|
||||||
type Value = D::Value;
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.0.expecting(formatter)
|
|
||||||
}
|
|
||||||
fn visit_bool<E>(self, v: bool) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_bool(v)
|
|
||||||
}
|
|
||||||
fn visit_i8<E>(self, v: i8) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i8(v)
|
|
||||||
}
|
|
||||||
fn visit_i16<E>(self, v: i16) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i16(v)
|
|
||||||
}
|
|
||||||
fn visit_i32<E>(self, v: i32) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i32(v)
|
|
||||||
}
|
|
||||||
fn visit_i64<E>(self, v: i64) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i64(v)
|
|
||||||
}
|
|
||||||
fn visit_u8<E>(self, v: u8) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u8(v)
|
|
||||||
}
|
|
||||||
fn visit_u16<E>(self, v: u16) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u16(v)
|
|
||||||
}
|
|
||||||
fn visit_u32<E>(self, v: u32) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u32(v)
|
|
||||||
}
|
|
||||||
fn visit_u64<E>(self, v: u64) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u64(v)
|
|
||||||
}
|
|
||||||
fn visit_f32<E>(self, v: f32) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_f32(v)
|
|
||||||
}
|
|
||||||
fn visit_f64<E>(self, v: f64) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_f64(v)
|
|
||||||
}
|
|
||||||
fn visit_char<E>(self, v: char) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_char(v)
|
|
||||||
}
|
|
||||||
fn visit_str<E>(self, v: &str) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_str(v)
|
|
||||||
}
|
|
||||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_borrowed_str(v)
|
|
||||||
}
|
|
||||||
fn visit_string<E>(self, v: String) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_string(v)
|
|
||||||
}
|
|
||||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_bytes(v)
|
|
||||||
}
|
|
||||||
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_borrowed_bytes(v)
|
|
||||||
}
|
|
||||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_byte_buf(v)
|
|
||||||
}
|
|
||||||
fn visit_none<E>(self) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_none()
|
|
||||||
}
|
|
||||||
fn visit_some<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
|
|
||||||
where
|
|
||||||
D2: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
self.0.visit_some($wrapper(deserializer))
|
|
||||||
}
|
|
||||||
fn visit_unit<E>(self) -> Result<D::Value, E>
|
|
||||||
where
|
|
||||||
E: Error,
|
|
||||||
{
|
|
||||||
self.0.visit_unit()
|
|
||||||
}
|
|
||||||
fn visit_newtype_struct<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
|
|
||||||
where
|
|
||||||
D2: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
self.0.visit_newtype_struct($wrapper(deserializer))
|
|
||||||
}
|
|
||||||
fn visit_seq<V>(self, seq: V) -> Result<D::Value, V::Error>
|
|
||||||
where
|
|
||||||
V: SeqAccess<'de>,
|
|
||||||
{
|
|
||||||
self.0.visit_seq($wrapper(seq))
|
|
||||||
}
|
|
||||||
fn visit_map<V>(self, map: V) -> Result<D::Value, V::Error>
|
|
||||||
where
|
|
||||||
V: MapAccess<'de>,
|
|
||||||
{
|
|
||||||
self.0.visit_map($wrapper(map))
|
|
||||||
}
|
|
||||||
fn visit_enum<V>(self, data: V) -> Result<D::Value, V::Error>
|
|
||||||
where
|
|
||||||
V: EnumAccess<'de>,
|
|
||||||
{
|
|
||||||
self.0.visit_enum($wrapper(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, D> SeqAccess<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: SeqAccess<'de>,
|
|
||||||
{
|
|
||||||
type Error = D::Error;
|
|
||||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, D::Error>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0.next_element_seed($wrapper(seed))
|
|
||||||
}
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
self.0.size_hint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, D> MapAccess<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: MapAccess<'de>,
|
|
||||||
{
|
|
||||||
type Error = D::Error;
|
|
||||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, D::Error>
|
|
||||||
where
|
|
||||||
K: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0.next_key_seed($wrapper(seed))
|
|
||||||
}
|
|
||||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0.next_value_seed($wrapper(seed))
|
|
||||||
}
|
|
||||||
fn next_entry_seed<K, V>(
|
|
||||||
&mut self,
|
|
||||||
kseed: K,
|
|
||||||
vseed: V,
|
|
||||||
) -> Result<Option<(K::Value, V::Value)>, D::Error>
|
|
||||||
where
|
|
||||||
K: DeserializeSeed<'de>,
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0.next_entry_seed($wrapper(kseed), $wrapper(vseed))
|
|
||||||
}
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
self.0.size_hint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, D> EnumAccess<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: EnumAccess<'de>,
|
|
||||||
{
|
|
||||||
type Error = D::Error;
|
|
||||||
type Variant = $wrapper<D::Variant>;
|
|
||||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
|
||||||
where
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0
|
|
||||||
.variant_seed($wrapper(seed))
|
|
||||||
.map(|(value, variant)| (value, $wrapper(variant)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, D> VariantAccess<'de> for $wrapper<D>
|
|
||||||
where
|
|
||||||
D: VariantAccess<'de>,
|
|
||||||
{
|
|
||||||
type Error = D::Error;
|
|
||||||
fn unit_variant(self) -> Result<(), D::Error> {
|
|
||||||
self.0.unit_variant()
|
|
||||||
}
|
|
||||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, D::Error>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
self.0.newtype_variant_seed($wrapper(seed))
|
|
||||||
}
|
|
||||||
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.tuple_variant(len, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
fn struct_variant<V>(
|
|
||||||
self,
|
|
||||||
fields: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, D::Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.0.struct_variant(fields, $wrapper(visitor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_deserializer!(Readable, true);
|
|
||||||
impl_deserializer!(Compact, false);
|
|
||||||
@@ -1,671 +0,0 @@
|
|||||||
use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
|
|
||||||
use serde::de::{
|
|
||||||
self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
|
|
||||||
VariantAccess, Visitor,
|
|
||||||
};
|
|
||||||
|
|
||||||
use error::Error;
|
|
||||||
use token::Token;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Deserializer<'de> {
|
|
||||||
tokens: &'de [Token],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_next_token(de: &mut Deserializer, expected: Token) -> Result<(), Error> {
|
|
||||||
match de.next_token_opt() {
|
|
||||||
Some(token) if token == expected => Ok(()),
|
|
||||||
Some(other) => Err(de::Error::custom(format!(
|
|
||||||
"expected Token::{} but deserialization wants Token::{}",
|
|
||||||
other, expected,
|
|
||||||
))),
|
|
||||||
None => Err(de::Error::custom(format!(
|
|
||||||
"end of tokens but deserialization wants Token::{}",
|
|
||||||
expected,
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unexpected(token: Token) -> Error {
|
|
||||||
de::Error::custom(format!(
|
|
||||||
"deserialization did not expect this token: {}",
|
|
||||||
token,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end_of_tokens() -> Error {
|
|
||||||
de::Error::custom("ran out of tokens to deserialize")
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserializer<'de> {
|
|
||||||
pub fn new(tokens: &'de [Token]) -> Self {
|
|
||||||
Deserializer { tokens: tokens }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peek_token_opt(&self) -> Option<Token> {
|
|
||||||
self.tokens.first().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peek_token(&self) -> Result<Token, Error> {
|
|
||||||
self.peek_token_opt().ok_or_else(end_of_tokens)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_token_opt(&mut self) -> Option<Token> {
|
|
||||||
match self.tokens.split_first() {
|
|
||||||
Some((&first, rest)) => {
|
|
||||||
self.tokens = rest;
|
|
||||||
Some(first)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_token(&mut self) -> Result<Token, Error> {
|
|
||||||
let (&first, rest) = self.tokens.split_first().ok_or_else(end_of_tokens)?;
|
|
||||||
self.tokens = rest;
|
|
||||||
Ok(first)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remaining(&self) -> usize {
|
|
||||||
self.tokens.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_seq<V>(
|
|
||||||
&mut self,
|
|
||||||
len: Option<usize>,
|
|
||||||
end: Token,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
let value = visitor.visit_seq(DeserializerSeqVisitor {
|
|
||||||
de: self,
|
|
||||||
len: len,
|
|
||||||
end: end,
|
|
||||||
})?;
|
|
||||||
assert_next_token(self, end)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_map<V>(
|
|
||||||
&mut self,
|
|
||||||
len: Option<usize>,
|
|
||||||
end: Token,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
let value = visitor.visit_map(DeserializerMapVisitor {
|
|
||||||
de: self,
|
|
||||||
len: len,
|
|
||||||
end: end,
|
|
||||||
})?;
|
|
||||||
assert_next_token(self, end)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
|
||||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
|
||||||
bytes byte_buf unit seq map identifier ignored_any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
let token = self.next_token()?;
|
|
||||||
match token {
|
|
||||||
Token::Bool(v) => visitor.visit_bool(v),
|
|
||||||
Token::I8(v) => visitor.visit_i8(v),
|
|
||||||
Token::I16(v) => visitor.visit_i16(v),
|
|
||||||
Token::I32(v) => visitor.visit_i32(v),
|
|
||||||
Token::I64(v) => visitor.visit_i64(v),
|
|
||||||
Token::U8(v) => visitor.visit_u8(v),
|
|
||||||
Token::U16(v) => visitor.visit_u16(v),
|
|
||||||
Token::U32(v) => visitor.visit_u32(v),
|
|
||||||
Token::U64(v) => visitor.visit_u64(v),
|
|
||||||
Token::F32(v) => visitor.visit_f32(v),
|
|
||||||
Token::F64(v) => visitor.visit_f64(v),
|
|
||||||
Token::Char(v) => visitor.visit_char(v),
|
|
||||||
Token::Str(v) => visitor.visit_str(v),
|
|
||||||
Token::BorrowedStr(v) => visitor.visit_borrowed_str(v),
|
|
||||||
Token::String(v) => visitor.visit_string(v.to_owned()),
|
|
||||||
Token::Bytes(v) => visitor.visit_bytes(v),
|
|
||||||
Token::BorrowedBytes(v) => visitor.visit_borrowed_bytes(v),
|
|
||||||
Token::ByteBuf(v) => visitor.visit_byte_buf(v.to_vec()),
|
|
||||||
Token::None => visitor.visit_none(),
|
|
||||||
Token::Some => visitor.visit_some(self),
|
|
||||||
Token::Unit | Token::UnitStruct { .. } => visitor.visit_unit(),
|
|
||||||
Token::NewtypeStruct { .. } => visitor.visit_newtype_struct(self),
|
|
||||||
Token::Seq { len } => self.visit_seq(len, Token::SeqEnd, visitor),
|
|
||||||
Token::Tuple { len } => self.visit_seq(Some(len), Token::TupleEnd, visitor),
|
|
||||||
Token::TupleStruct { len, .. } => {
|
|
||||||
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::Map { len } => self.visit_map(len, Token::MapEnd, visitor),
|
|
||||||
Token::Struct { len, .. } => self.visit_map(Some(len), Token::StructEnd, visitor),
|
|
||||||
Token::Enum { .. } => {
|
|
||||||
let variant = self.next_token()?;
|
|
||||||
let next = self.peek_token()?;
|
|
||||||
match (variant, next) {
|
|
||||||
(Token::Str(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_str(variant)
|
|
||||||
}
|
|
||||||
(Token::BorrowedStr(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_borrowed_str(variant)
|
|
||||||
}
|
|
||||||
(Token::String(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_string(variant.to_string())
|
|
||||||
}
|
|
||||||
(Token::Bytes(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_bytes(variant)
|
|
||||||
}
|
|
||||||
(Token::BorrowedBytes(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_borrowed_bytes(variant)
|
|
||||||
}
|
|
||||||
(Token::ByteBuf(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_byte_buf(variant.to_vec())
|
|
||||||
}
|
|
||||||
(Token::U8(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_u8(variant)
|
|
||||||
}
|
|
||||||
(Token::U16(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_u16(variant)
|
|
||||||
}
|
|
||||||
(Token::U32(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_u32(variant)
|
|
||||||
}
|
|
||||||
(Token::U64(variant), Token::Unit) => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_u64(variant)
|
|
||||||
}
|
|
||||||
(variant, Token::Unit) => Err(unexpected(variant)),
|
|
||||||
(variant, _) => {
|
|
||||||
visitor.visit_map(EnumMapVisitor::new(self, variant, EnumFormat::Any))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Token::UnitVariant { variant, .. } => visitor.visit_str(variant),
|
|
||||||
Token::NewtypeVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
|
|
||||||
self,
|
|
||||||
Token::Str(variant),
|
|
||||||
EnumFormat::Any,
|
|
||||||
)),
|
|
||||||
Token::TupleVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
|
|
||||||
self,
|
|
||||||
Token::Str(variant),
|
|
||||||
EnumFormat::Seq,
|
|
||||||
)),
|
|
||||||
Token::StructVariant { variant, .. } => visitor.visit_map(EnumMapVisitor::new(
|
|
||||||
self,
|
|
||||||
Token::Str(variant),
|
|
||||||
EnumFormat::Map,
|
|
||||||
)),
|
|
||||||
Token::SeqEnd
|
|
||||||
| Token::TupleEnd
|
|
||||||
| Token::TupleStructEnd
|
|
||||||
| Token::MapEnd
|
|
||||||
| Token::StructEnd
|
|
||||||
| Token::TupleVariantEnd
|
|
||||||
| Token::StructVariantEnd => Err(unexpected(token)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::Unit | Token::None => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_none()
|
|
||||||
}
|
|
||||||
Token::Some => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_some(self)
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_variants: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::Enum { name: n } if name == n => {
|
|
||||||
self.next_token()?;
|
|
||||||
|
|
||||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
|
||||||
}
|
|
||||||
Token::UnitVariant { name: n, .. }
|
|
||||||
| Token::NewtypeVariant { name: n, .. }
|
|
||||||
| Token::TupleVariant { name: n, .. }
|
|
||||||
| Token::StructVariant { name: n, .. }
|
|
||||||
if name == n =>
|
|
||||||
{
|
|
||||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::UnitStruct { .. } => {
|
|
||||||
assert_next_token(self, Token::UnitStruct { name: name })?;
|
|
||||||
visitor.visit_unit()
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::NewtypeStruct { .. } => {
|
|
||||||
assert_next_token(self, Token::NewtypeStruct { name: name })?;
|
|
||||||
visitor.visit_newtype_struct(self)
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::Unit | Token::UnitStruct { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_unit()
|
|
||||||
}
|
|
||||||
Token::Seq { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::Tuple { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::TupleStruct { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_tuple_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
len: usize,
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::Unit => {
|
|
||||||
self.next_token()?;
|
|
||||||
visitor.visit_unit()
|
|
||||||
}
|
|
||||||
Token::UnitStruct { .. } => {
|
|
||||||
assert_next_token(self, Token::UnitStruct { name: name })?;
|
|
||||||
visitor.visit_unit()
|
|
||||||
}
|
|
||||||
Token::Seq { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_seq(Some(len), Token::SeqEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::Tuple { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_seq(Some(len), Token::TupleEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::TupleStruct { len: n, .. } => {
|
|
||||||
assert_next_token(self, Token::TupleStruct { name: name, len: n })?;
|
|
||||||
self.visit_seq(Some(len), Token::TupleStructEnd, visitor)
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_struct<V>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
fields: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.peek_token()? {
|
|
||||||
Token::Struct { len: n, .. } => {
|
|
||||||
assert_next_token(self, Token::Struct { name: name, len: n })?;
|
|
||||||
self.visit_map(Some(fields.len()), Token::StructEnd, visitor)
|
|
||||||
}
|
|
||||||
Token::Map { .. } => {
|
|
||||||
self.next_token()?;
|
|
||||||
self.visit_map(Some(fields.len()), Token::MapEnd, visitor)
|
|
||||||
}
|
|
||||||
_ => self.deserialize_any(visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
|
||||||
panic!(
|
|
||||||
"Types which have different human-readable and compact representations \
|
|
||||||
must explicitly mark their test cases with `serde_test::Configure`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct DeserializerSeqVisitor<'a, 'de: 'a> {
|
|
||||||
de: &'a mut Deserializer<'de>,
|
|
||||||
len: Option<usize>,
|
|
||||||
end: Token,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> SeqAccess<'de> for DeserializerSeqVisitor<'a, 'de> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
if self.de.peek_token_opt() == Some(self.end) {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
self.len = self.len.map(|len| len.saturating_sub(1));
|
|
||||||
seed.deserialize(&mut *self.de).map(Some)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct DeserializerMapVisitor<'a, 'de: 'a> {
|
|
||||||
de: &'a mut Deserializer<'de>,
|
|
||||||
len: Option<usize>,
|
|
||||||
end: Token,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> MapAccess<'de> for DeserializerMapVisitor<'a, 'de> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
|
|
||||||
where
|
|
||||||
K: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
if self.de.peek_token_opt() == Some(self.end) {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
self.len = self.len.map(|len| len.saturating_sub(1));
|
|
||||||
seed.deserialize(&mut *self.de).map(Some)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
seed.deserialize(&mut *self.de)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> Option<usize> {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct DeserializerEnumVisitor<'a, 'de: 'a> {
|
|
||||||
de: &'a mut Deserializer<'de>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|
||||||
type Error = Error;
|
|
||||||
type Variant = Self;
|
|
||||||
|
|
||||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self), Error>
|
|
||||||
where
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.de.peek_token()? {
|
|
||||||
Token::UnitVariant { variant: v, .. }
|
|
||||||
| Token::NewtypeVariant { variant: v, .. }
|
|
||||||
| Token::TupleVariant { variant: v, .. }
|
|
||||||
| Token::StructVariant { variant: v, .. } => {
|
|
||||||
let de = v.into_deserializer();
|
|
||||||
let value = seed.deserialize(de)?;
|
|
||||||
Ok((value, self))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let value = seed.deserialize(&mut *self.de)?;
|
|
||||||
Ok((value, self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> VariantAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn unit_variant(self) -> Result<(), Error> {
|
|
||||||
match self.de.peek_token()? {
|
|
||||||
Token::UnitVariant { .. } => {
|
|
||||||
self.de.next_token()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Deserialize::deserialize(self.de),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
|
|
||||||
where
|
|
||||||
T: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.de.peek_token()? {
|
|
||||||
Token::NewtypeVariant { .. } => {
|
|
||||||
self.de.next_token()?;
|
|
||||||
seed.deserialize(self.de)
|
|
||||||
}
|
|
||||||
_ => seed.deserialize(self.de),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.de.peek_token()? {
|
|
||||||
Token::TupleVariant { len: enum_len, .. } => {
|
|
||||||
let token = self.de.next_token()?;
|
|
||||||
|
|
||||||
if len == enum_len {
|
|
||||||
self.de
|
|
||||||
.visit_seq(Some(len), Token::TupleVariantEnd, visitor)
|
|
||||||
} else {
|
|
||||||
Err(unexpected(token))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Token::Seq {
|
|
||||||
len: Some(enum_len),
|
|
||||||
} => {
|
|
||||||
let token = self.de.next_token()?;
|
|
||||||
|
|
||||||
if len == enum_len {
|
|
||||||
self.de.visit_seq(Some(len), Token::SeqEnd, visitor)
|
|
||||||
} else {
|
|
||||||
Err(unexpected(token))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => de::Deserializer::deserialize_any(self.de, visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn struct_variant<V>(
|
|
||||||
self,
|
|
||||||
fields: &'static [&'static str],
|
|
||||||
visitor: V,
|
|
||||||
) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
match self.de.peek_token()? {
|
|
||||||
Token::StructVariant { len: enum_len, .. } => {
|
|
||||||
let token = self.de.next_token()?;
|
|
||||||
|
|
||||||
if fields.len() == enum_len {
|
|
||||||
self.de
|
|
||||||
.visit_map(Some(fields.len()), Token::StructVariantEnd, visitor)
|
|
||||||
} else {
|
|
||||||
Err(unexpected(token))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Token::Map {
|
|
||||||
len: Some(enum_len),
|
|
||||||
} => {
|
|
||||||
let token = self.de.next_token()?;
|
|
||||||
|
|
||||||
if fields.len() == enum_len {
|
|
||||||
self.de
|
|
||||||
.visit_map(Some(fields.len()), Token::MapEnd, visitor)
|
|
||||||
} else {
|
|
||||||
Err(unexpected(token))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => de::Deserializer::deserialize_any(self.de, visitor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct EnumMapVisitor<'a, 'de: 'a> {
|
|
||||||
de: &'a mut Deserializer<'de>,
|
|
||||||
variant: Option<Token>,
|
|
||||||
format: EnumFormat,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum EnumFormat {
|
|
||||||
Seq,
|
|
||||||
Map,
|
|
||||||
Any,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'de> EnumMapVisitor<'a, 'de> {
|
|
||||||
fn new(de: &'a mut Deserializer<'de>, variant: Token, format: EnumFormat) -> Self {
|
|
||||||
EnumMapVisitor {
|
|
||||||
de: de,
|
|
||||||
variant: Some(variant),
|
|
||||||
format: format,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
|
|
||||||
where
|
|
||||||
K: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.variant.take() {
|
|
||||||
Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
|
|
||||||
Some(Token::Bytes(variant)) => seed
|
|
||||||
.deserialize(BytesDeserializer { value: variant })
|
|
||||||
.map(Some),
|
|
||||||
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
|
|
||||||
Some(other) => Err(unexpected(other)),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
|
|
||||||
where
|
|
||||||
V: DeserializeSeed<'de>,
|
|
||||||
{
|
|
||||||
match self.format {
|
|
||||||
EnumFormat::Seq => {
|
|
||||||
let value = {
|
|
||||||
let visitor = DeserializerSeqVisitor {
|
|
||||||
de: self.de,
|
|
||||||
len: None,
|
|
||||||
end: Token::TupleVariantEnd,
|
|
||||||
};
|
|
||||||
seed.deserialize(SeqAccessDeserializer::new(visitor))?
|
|
||||||
};
|
|
||||||
assert_next_token(self.de, Token::TupleVariantEnd)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
EnumFormat::Map => {
|
|
||||||
let value = {
|
|
||||||
let visitor = DeserializerMapVisitor {
|
|
||||||
de: self.de,
|
|
||||||
len: None,
|
|
||||||
end: Token::StructVariantEnd,
|
|
||||||
};
|
|
||||||
seed.deserialize(MapAccessDeserializer::new(visitor))?
|
|
||||||
};
|
|
||||||
assert_next_token(self.de, Token::StructVariantEnd)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
EnumFormat::Any => seed.deserialize(&mut *self.de),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BytesDeserializer {
|
|
||||||
value: &'static [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> de::Deserializer<'de> for BytesDeserializer {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
|
||||||
where
|
|
||||||
V: de::Visitor<'de>,
|
|
||||||
{
|
|
||||||
visitor.visit_bytes(self.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
|
||||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
|
||||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
|
||||||
tuple_struct map struct enum identifier ignored_any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
use std::error;
|
|
||||||
use std::fmt::{self, Display};
|
|
||||||
|
|
||||||
use serde::{de, ser};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Error {
|
|
||||||
msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ser::Error for Error {
|
|
||||||
fn custom<T: Display>(msg: T) -> Self {
|
|
||||||
Error {
|
|
||||||
msg: msg.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl de::Error for Error {
|
|
||||||
fn custom<T: Display>(msg: T) -> Self {
|
|
||||||
Error {
|
|
||||||
msg: msg.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str(&self.msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
&self.msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<str> for Error {
|
|
||||||
fn eq(&self, other: &str) -> bool {
|
|
||||||
self.msg == other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
//! This crate provides a convenient concise way to write unit tests for
|
|
||||||
//! implementations of [`Serialize`] and [`Deserialize`].
|
|
||||||
//!
|
|
||||||
//! [`Serialize`]: serde::ser::Serialize
|
|
||||||
//! [`Deserialize`]: serde::de::Deserialize
|
|
||||||
//!
|
|
||||||
//! The `Serialize` impl for a value can be characterized by the sequence of
|
|
||||||
//! [`Serializer`] calls that are made in the course of serializing the value,
|
|
||||||
//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly
|
|
||||||
//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to
|
|
||||||
//! test that a value serializes to a particular sequence of method calls, an
|
|
||||||
//! [`assert_de_tokens`] function to test that a value can be deserialized from
|
|
||||||
//! a particular sequence of method calls, and an [`assert_tokens`] function to
|
|
||||||
//! test both directions. There are also functions to test expected failure
|
|
||||||
//! conditions.
|
|
||||||
//!
|
|
||||||
//! [`Serializer`]: serde::ser::Serializer
|
|
||||||
//!
|
|
||||||
//! Here is an example from the [`linked-hash-map`] crate.
|
|
||||||
//!
|
|
||||||
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
|
|
||||||
//!
|
|
||||||
//! ```edition2018
|
|
||||||
//! # const IGNORE: &str = stringify! {
|
|
||||||
//! use linked_hash_map::LinkedHashMap;
|
|
||||||
//! # };
|
|
||||||
//! use serde_test::{Token, assert_tokens};
|
|
||||||
//!
|
|
||||||
//! # use std::fmt;
|
|
||||||
//! # use std::marker::PhantomData;
|
|
||||||
//! #
|
|
||||||
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
|
|
||||||
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
|
|
||||||
//! #
|
|
||||||
//! # // Dumb imitation of LinkedHashMap.
|
|
||||||
//! # #[derive(PartialEq, Debug)]
|
|
||||||
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
|
|
||||||
//! #
|
|
||||||
//! # impl<K, V> LinkedHashMap<K, V> {
|
|
||||||
//! # fn new() -> Self {
|
|
||||||
//! # LinkedHashMap(Vec::new())
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # fn insert(&mut self, k: K, v: V) {
|
|
||||||
//! # self.0.push((k, v));
|
|
||||||
//! # }
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
|
|
||||||
//! # where
|
|
||||||
//! # K: Serialize,
|
|
||||||
//! # V: Serialize,
|
|
||||||
//! # {
|
|
||||||
//! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
//! # where
|
|
||||||
//! # S: Serializer,
|
|
||||||
//! # {
|
|
||||||
//! # let mut map = serializer.serialize_map(Some(self.0.len()))?;
|
|
||||||
//! # for &(ref k, ref v) in &self.0 {
|
|
||||||
//! # map.serialize_entry(k, v)?;
|
|
||||||
//! # }
|
|
||||||
//! # map.end()
|
|
||||||
//! # }
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
|
|
||||||
//! #
|
|
||||||
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
|
|
||||||
//! # where
|
|
||||||
//! # K: Deserialize<'de>,
|
|
||||||
//! # V: Deserialize<'de>,
|
|
||||||
//! # {
|
|
||||||
//! # type Value = LinkedHashMap<K, V>;
|
|
||||||
//! #
|
|
||||||
//! # fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
//! # unimplemented!()
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
|
||||||
//! # where
|
|
||||||
//! # M: MapAccess<'de>,
|
|
||||||
//! # {
|
|
||||||
//! # let mut map = LinkedHashMap::new();
|
|
||||||
//! # while let Some((key, value)) = access.next_entry()? {
|
|
||||||
//! # map.insert(key, value);
|
|
||||||
//! # }
|
|
||||||
//! # Ok(map)
|
|
||||||
//! # }
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
|
|
||||||
//! # where
|
|
||||||
//! # K: Deserialize<'de>,
|
|
||||||
//! # V: Deserialize<'de>,
|
|
||||||
//! # {
|
|
||||||
//! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
//! # where
|
|
||||||
//! # D: Deserializer<'de>,
|
|
||||||
//! # {
|
|
||||||
//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
|
|
||||||
//! # }
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! #[test]
|
|
||||||
//! # fn not_a_test_ser_de_empty() {}
|
|
||||||
//! fn test_ser_de_empty() {
|
|
||||||
//! let map = LinkedHashMap::<char, u32>::new();
|
|
||||||
//!
|
|
||||||
//! assert_tokens(&map, &[
|
|
||||||
//! Token::Map { len: Some(0) },
|
|
||||||
//! Token::MapEnd,
|
|
||||||
//! ]);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! #[test]
|
|
||||||
//! # fn not_a_test_ser_de() {}
|
|
||||||
//! fn test_ser_de() {
|
|
||||||
//! let mut map = LinkedHashMap::new();
|
|
||||||
//! map.insert('b', 20);
|
|
||||||
//! map.insert('a', 10);
|
|
||||||
//! map.insert('c', 30);
|
|
||||||
//!
|
|
||||||
//! assert_tokens(&map, &[
|
|
||||||
//! Token::Map { len: Some(3) },
|
|
||||||
//! Token::Char('b'),
|
|
||||||
//! Token::I32(20),
|
|
||||||
//!
|
|
||||||
//! Token::Char('a'),
|
|
||||||
//! Token::I32(10),
|
|
||||||
//!
|
|
||||||
//! Token::Char('c'),
|
|
||||||
//! Token::I32(30),
|
|
||||||
//! Token::MapEnd,
|
|
||||||
//! ]);
|
|
||||||
//! }
|
|
||||||
//! #
|
|
||||||
//! # fn main() {
|
|
||||||
//! # test_ser_de_empty();
|
|
||||||
//! # test_ser_de();
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.165")]
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
|
||||||
// Ignored clippy lints
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
|
|
||||||
// Ignored clippy_pedantic lints
|
|
||||||
#![cfg_attr(
|
|
||||||
feature = "cargo-clippy",
|
|
||||||
allow(
|
|
||||||
cloned_instead_of_copied,
|
|
||||||
doc_link_with_quotes, // https://github.com/rust-lang/rust-clippy/issues/8961
|
|
||||||
empty_line_after_outer_attr,
|
|
||||||
manual_assert,
|
|
||||||
missing_docs_in_private_items,
|
|
||||||
missing_panics_doc,
|
|
||||||
module_name_repetitions,
|
|
||||||
must_use_candidate,
|
|
||||||
redundant_field_names,
|
|
||||||
too_many_lines,
|
|
||||||
type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
|
||||||
use_debug,
|
|
||||||
use_self
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
mod de;
|
|
||||||
mod error;
|
|
||||||
mod ser;
|
|
||||||
|
|
||||||
mod assert;
|
|
||||||
mod configure;
|
|
||||||
mod token;
|
|
||||||
|
|
||||||
pub use assert::{
|
|
||||||
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
|
|
||||||
assert_tokens,
|
|
||||||
};
|
|
||||||
pub use token::Token;
|
|
||||||
|
|
||||||
pub use configure::{Compact, Configure, Readable};
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
use serde::{ser, Serialize};
|
|
||||||
|
|
||||||
use error::Error;
|
|
||||||
use token::Token;
|
|
||||||
|
|
||||||
/// A `Serializer` that ensures that a value serializes to a given list of
|
|
||||||
/// tokens.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Serializer<'a> {
|
|
||||||
tokens: &'a [Token],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Serializer<'a> {
|
|
||||||
/// Creates the serializer.
|
|
||||||
pub fn new(tokens: &'a [Token]) -> Self {
|
|
||||||
Serializer { tokens: tokens }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pulls the next token off of the serializer, ignoring it.
|
|
||||||
fn next_token(&mut self) -> Option<Token> {
|
|
||||||
if let Some((&first, rest)) = self.tokens.split_first() {
|
|
||||||
self.tokens = rest;
|
|
||||||
Some(first)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remaining(&self) -> usize {
|
|
||||||
self.tokens.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_next_token {
|
|
||||||
($ser:expr, $actual:ident) => {{
|
|
||||||
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
|
|
||||||
}};
|
|
||||||
($ser:expr, $actual:ident($v:expr)) => {{
|
|
||||||
assert_next_token!(
|
|
||||||
$ser,
|
|
||||||
format_args!(concat!(stringify!($actual), "({:?})"), $v),
|
|
||||||
Token::$actual(v),
|
|
||||||
v == $v
|
|
||||||
);
|
|
||||||
}};
|
|
||||||
($ser:expr, $actual:ident { $($k:ident),* }) => {{
|
|
||||||
let compare = ($($k,)*);
|
|
||||||
let field_format = || {
|
|
||||||
use std::fmt::Write;
|
|
||||||
let mut buffer = String::new();
|
|
||||||
$(
|
|
||||||
write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap();
|
|
||||||
)*
|
|
||||||
buffer
|
|
||||||
};
|
|
||||||
assert_next_token!(
|
|
||||||
$ser,
|
|
||||||
format_args!(concat!(stringify!($actual), " {{ {}}}"), field_format()),
|
|
||||||
Token::$actual { $($k),* },
|
|
||||||
($($k,)*) == compare
|
|
||||||
);
|
|
||||||
}};
|
|
||||||
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
|
|
||||||
match $ser.next_token() {
|
|
||||||
Some($pat) if $guard => {}
|
|
||||||
Some(expected) => return Err(ser::Error::custom(
|
|
||||||
format!("expected Token::{} but serialized as {}", expected, $actual)
|
|
||||||
)),
|
|
||||||
None => return Err(ser::Error::custom(
|
|
||||||
format!("expected end of tokens, but {} was serialized", $actual)
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
type SerializeSeq = Self;
|
|
||||||
type SerializeTuple = Self;
|
|
||||||
type SerializeTupleStruct = Self;
|
|
||||||
type SerializeTupleVariant = Variant<'s, 'a>;
|
|
||||||
type SerializeMap = Self;
|
|
||||||
type SerializeStruct = Self;
|
|
||||||
type SerializeStructVariant = Variant<'s, 'a>;
|
|
||||||
|
|
||||||
fn serialize_bool(self, v: bool) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, Bool(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_i8(self, v: i8) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, I8(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_i16(self, v: i16) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, I16(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_i32(self, v: i32) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, I32(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_i64(self, v: i64) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, I64(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_u8(self, v: u8) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, U8(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_u16(self, v: u16) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, U16(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_u32(self, v: u32) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, U32(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_u64(self, v: u64) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, U64(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_f32(self, v: f32) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, F32(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_f64(self, v: f64) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, F64(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_char(self, v: char) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, Char(v));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_str(self, v: &str) -> Result<(), Error> {
|
|
||||||
match self.tokens.first() {
|
|
||||||
Some(&Token::BorrowedStr(_)) => assert_next_token!(self, BorrowedStr(v)),
|
|
||||||
Some(&Token::String(_)) => assert_next_token!(self, String(v)),
|
|
||||||
_ => assert_next_token!(self, Str(v)),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
match self.tokens.first() {
|
|
||||||
Some(&Token::BorrowedBytes(_)) => assert_next_token!(self, BorrowedBytes(v)),
|
|
||||||
Some(&Token::ByteBuf(_)) => assert_next_token!(self, ByteBuf(v)),
|
|
||||||
_ => assert_next_token!(self, Bytes(v)),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, Unit);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit_struct(self, name: &'static str) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, UnitStruct { name });
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
|
||||||
self.next_token();
|
|
||||||
assert_next_token!(self, Str(variant));
|
|
||||||
assert_next_token!(self, Unit);
|
|
||||||
} else {
|
|
||||||
assert_next_token!(self, UnitVariant { name, variant });
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
assert_next_token!(self, NewtypeStruct { name });
|
|
||||||
value.serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_newtype_variant<T: ?Sized>(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
|
||||||
self.next_token();
|
|
||||||
assert_next_token!(self, Str(variant));
|
|
||||||
} else {
|
|
||||||
assert_next_token!(self, NewtypeVariant { name, variant });
|
|
||||||
}
|
|
||||||
value.serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, None);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
assert_next_token!(self, Some);
|
|
||||||
value.serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self, Error> {
|
|
||||||
assert_next_token!(self, Seq { len });
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple(self, len: usize) -> Result<Self, Error> {
|
|
||||||
assert_next_token!(self, Tuple { len });
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
|
|
||||||
assert_next_token!(self, TupleStruct { name, len });
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_tuple_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeTupleVariant, Error> {
|
|
||||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
|
||||||
self.next_token();
|
|
||||||
assert_next_token!(self, Str(variant));
|
|
||||||
let len = Some(len);
|
|
||||||
assert_next_token!(self, Seq { len });
|
|
||||||
Ok(Variant {
|
|
||||||
ser: self,
|
|
||||||
end: Token::SeqEnd,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
assert_next_token!(self, TupleVariant { name, variant, len });
|
|
||||||
Ok(Variant {
|
|
||||||
ser: self,
|
|
||||||
end: Token::TupleVariantEnd,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_map(self, len: Option<usize>) -> Result<Self, Error> {
|
|
||||||
assert_next_token!(self, Map { len });
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
|
|
||||||
assert_next_token!(self, Struct { name, len });
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_struct_variant(
|
|
||||||
self,
|
|
||||||
name: &'static str,
|
|
||||||
_variant_index: u32,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
) -> Result<Self::SerializeStructVariant, Error> {
|
|
||||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
|
||||||
self.next_token();
|
|
||||||
assert_next_token!(self, Str(variant));
|
|
||||||
let len = Some(len);
|
|
||||||
assert_next_token!(self, Map { len });
|
|
||||||
Ok(Variant {
|
|
||||||
ser: self,
|
|
||||||
end: Token::MapEnd,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
assert_next_token!(self, StructVariant { name, variant, len });
|
|
||||||
Ok(Variant {
|
|
||||||
ser: self,
|
|
||||||
end: Token::StructVariantEnd,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_human_readable(&self) -> bool {
|
|
||||||
panic!(
|
|
||||||
"Types which have different human-readable and compact representations \
|
|
||||||
must explicitly mark their test cases with `serde_test::Configure`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Variant<'s, 'a: 's> {
|
|
||||||
ser: &'s mut Serializer<'a>,
|
|
||||||
end: Token,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeSeq for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
value.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, SeqEnd);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeTuple for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
value.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, TupleEnd);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeTupleStruct for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
value.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Error> {
|
|
||||||
assert_next_token!(self, TupleStructEnd);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeTupleVariant for Variant<'s, 'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
value.serialize(&mut *self.ser)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Error> {
|
|
||||||
match self.end {
|
|
||||||
Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd),
|
|
||||||
Token::SeqEnd => assert_next_token!(self.ser, SeqEnd),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeMap for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
key.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
value.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Self::Error> {
|
|
||||||
assert_next_token!(self, MapEnd);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(
|
|
||||||
&mut self,
|
|
||||||
key: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Self::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
key.serialize(&mut **self)?;
|
|
||||||
value.serialize(&mut **self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Self::Error> {
|
|
||||||
assert_next_token!(self, StructEnd);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> {
|
|
||||||
type Ok = ();
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized>(
|
|
||||||
&mut self,
|
|
||||||
key: &'static str,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Self::Error>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
key.serialize(&mut *self.ser)?;
|
|
||||||
value.serialize(&mut *self.ser)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<(), Self::Error> {
|
|
||||||
match self.end {
|
|
||||||
Token::StructVariantEnd => assert_next_token!(self.ser, StructVariantEnd),
|
|
||||||
Token::MapEnd => assert_next_token!(self.ser, MapEnd),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,519 +0,0 @@
|
|||||||
use std::fmt::{self, Debug, Display};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
||||||
pub enum Token {
|
|
||||||
/// A serialized `bool`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&true, &[Token::Bool(true)]);
|
|
||||||
/// ```
|
|
||||||
Bool(bool),
|
|
||||||
|
|
||||||
/// A serialized `i8`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i8, &[Token::I8(0)]);
|
|
||||||
/// ```
|
|
||||||
I8(i8),
|
|
||||||
|
|
||||||
/// A serialized `i16`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i16, &[Token::I16(0)]);
|
|
||||||
/// ```
|
|
||||||
I16(i16),
|
|
||||||
|
|
||||||
/// A serialized `i32`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i32, &[Token::I32(0)]);
|
|
||||||
/// ```
|
|
||||||
I32(i32),
|
|
||||||
|
|
||||||
/// A serialized `i64`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i64, &[Token::I64(0)]);
|
|
||||||
/// ```
|
|
||||||
I64(i64),
|
|
||||||
|
|
||||||
/// A serialized `u8`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u8, &[Token::U8(0)]);
|
|
||||||
/// ```
|
|
||||||
U8(u8),
|
|
||||||
|
|
||||||
/// A serialized `u16`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u16, &[Token::U16(0)]);
|
|
||||||
/// ```
|
|
||||||
U16(u16),
|
|
||||||
|
|
||||||
/// A serialized `u32`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u32, &[Token::U32(0)]);
|
|
||||||
/// ```
|
|
||||||
U32(u32),
|
|
||||||
|
|
||||||
/// A serialized `u64`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u64, &[Token::U64(0)]);
|
|
||||||
/// ```
|
|
||||||
U64(u64),
|
|
||||||
|
|
||||||
/// A serialized `f32`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
|
|
||||||
/// ```
|
|
||||||
F32(f32),
|
|
||||||
|
|
||||||
/// A serialized `f64`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
|
|
||||||
/// ```
|
|
||||||
F64(f64),
|
|
||||||
|
|
||||||
/// A serialized `char`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&'\n', &[Token::Char('\n')]);
|
|
||||||
/// ```
|
|
||||||
Char(char),
|
|
||||||
|
|
||||||
/// A serialized `str`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let s = String::from("transient");
|
|
||||||
/// assert_tokens(&s, &[Token::Str("transient")]);
|
|
||||||
/// ```
|
|
||||||
Str(&'static str),
|
|
||||||
|
|
||||||
/// A borrowed `str`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let s: &str = "borrowed";
|
|
||||||
/// assert_tokens(&s, &[Token::BorrowedStr("borrowed")]);
|
|
||||||
/// ```
|
|
||||||
BorrowedStr(&'static str),
|
|
||||||
|
|
||||||
/// A serialized `String`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let s = String::from("owned");
|
|
||||||
/// assert_tokens(&s, &[Token::String("owned")]);
|
|
||||||
/// ```
|
|
||||||
String(&'static str),
|
|
||||||
|
|
||||||
/// A serialized `[u8]`
|
|
||||||
Bytes(&'static [u8]),
|
|
||||||
|
|
||||||
/// A borrowed `[u8]`.
|
|
||||||
BorrowedBytes(&'static [u8]),
|
|
||||||
|
|
||||||
/// A serialized `ByteBuf`
|
|
||||||
ByteBuf(&'static [u8]),
|
|
||||||
|
|
||||||
/// A serialized `Option<T>` containing none.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let opt = None::<char>;
|
|
||||||
/// assert_tokens(&opt, &[Token::None]);
|
|
||||||
/// ```
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// The header to a serialized `Option<T>` containing some value.
|
|
||||||
///
|
|
||||||
/// The tokens of the value follow after this header.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let opt = Some('c');
|
|
||||||
/// assert_tokens(&opt, &[
|
|
||||||
/// Token::Some,
|
|
||||||
/// Token::Char('c'),
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
Some,
|
|
||||||
|
|
||||||
/// A serialized `()`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&(), &[Token::Unit]);
|
|
||||||
/// ```
|
|
||||||
Unit,
|
|
||||||
|
|
||||||
/// A serialized unit struct of the given name.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct X;
|
|
||||||
///
|
|
||||||
/// assert_tokens(&X, &[Token::UnitStruct { name: "X" }]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
UnitStruct { name: &'static str },
|
|
||||||
|
|
||||||
/// A unit variant of an enum.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// enum E {
|
|
||||||
/// A,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let a = E::A;
|
|
||||||
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
UnitVariant {
|
|
||||||
name: &'static str,
|
|
||||||
variant: &'static str,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The header to a serialized newtype struct of the given name.
|
|
||||||
///
|
|
||||||
/// After this header is the value contained in the newtype struct.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct N(String);
|
|
||||||
///
|
|
||||||
/// let n = N("newtype".to_owned());
|
|
||||||
/// assert_tokens(&n, &[
|
|
||||||
/// Token::NewtypeStruct { name: "N" },
|
|
||||||
/// Token::String("newtype"),
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
NewtypeStruct { name: &'static str },
|
|
||||||
|
|
||||||
/// The header to a newtype variant of an enum.
|
|
||||||
///
|
|
||||||
/// After this header is the value contained in the newtype variant.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// enum E {
|
|
||||||
/// B(u8),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let b = E::B(0);
|
|
||||||
/// assert_tokens(&b, &[
|
|
||||||
/// Token::NewtypeVariant { name: "E", variant: "B" },
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
NewtypeVariant {
|
|
||||||
name: &'static str,
|
|
||||||
variant: &'static str,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The header to a sequence.
|
|
||||||
///
|
|
||||||
/// After this header are the elements of the sequence, followed by
|
|
||||||
/// `SeqEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let vec = vec!['a', 'b', 'c'];
|
|
||||||
/// assert_tokens(&vec, &[
|
|
||||||
/// Token::Seq { len: Some(3) },
|
|
||||||
/// Token::Char('a'),
|
|
||||||
/// Token::Char('b'),
|
|
||||||
/// Token::Char('c'),
|
|
||||||
/// Token::SeqEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
Seq { len: Option<usize> },
|
|
||||||
|
|
||||||
/// An indicator of the end of a sequence.
|
|
||||||
SeqEnd,
|
|
||||||
|
|
||||||
/// The header to a tuple.
|
|
||||||
///
|
|
||||||
/// After this header are the elements of the tuple, followed by `TupleEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let tuple = ('a', 100);
|
|
||||||
/// assert_tokens(&tuple, &[
|
|
||||||
/// Token::Tuple { len: 2 },
|
|
||||||
/// Token::Char('a'),
|
|
||||||
/// Token::I32(100),
|
|
||||||
/// Token::TupleEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
Tuple { len: usize },
|
|
||||||
|
|
||||||
/// An indicator of the end of a tuple.
|
|
||||||
TupleEnd,
|
|
||||||
|
|
||||||
/// The header to a tuple struct.
|
|
||||||
///
|
|
||||||
/// After this header are the fields of the tuple struct, followed by
|
|
||||||
/// `TupleStructEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct T(u8, u8);
|
|
||||||
///
|
|
||||||
/// let t = T(0, 0);
|
|
||||||
/// assert_tokens(&t, &[
|
|
||||||
/// Token::TupleStruct { name: "T", len: 2 },
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::TupleStructEnd,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
TupleStruct { name: &'static str, len: usize },
|
|
||||||
|
|
||||||
/// An indicator of the end of a tuple struct.
|
|
||||||
TupleStructEnd,
|
|
||||||
|
|
||||||
/// The header to a tuple variant of an enum.
|
|
||||||
///
|
|
||||||
/// After this header are the fields of the tuple variant, followed by
|
|
||||||
/// `TupleVariantEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// enum E {
|
|
||||||
/// C(u8, u8),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let c = E::C(0, 0);
|
|
||||||
/// assert_tokens(&c, &[
|
|
||||||
/// Token::TupleVariant { name: "E", variant: "C", len: 2 },
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::TupleVariantEnd,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
TupleVariant {
|
|
||||||
name: &'static str,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// An indicator of the end of a tuple variant.
|
|
||||||
TupleVariantEnd,
|
|
||||||
|
|
||||||
/// The header to a map.
|
|
||||||
///
|
|
||||||
/// After this header are the entries of the map, followed by `MapEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// use std::collections::BTreeMap;
|
|
||||||
///
|
|
||||||
/// let mut map = BTreeMap::new();
|
|
||||||
/// map.insert('A', 65);
|
|
||||||
/// map.insert('Z', 90);
|
|
||||||
///
|
|
||||||
/// assert_tokens(&map, &[
|
|
||||||
/// Token::Map { len: Some(2) },
|
|
||||||
/// Token::Char('A'),
|
|
||||||
/// Token::I32(65),
|
|
||||||
/// Token::Char('Z'),
|
|
||||||
/// Token::I32(90),
|
|
||||||
/// Token::MapEnd,
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
Map { len: Option<usize> },
|
|
||||||
|
|
||||||
/// An indicator of the end of a map.
|
|
||||||
MapEnd,
|
|
||||||
|
|
||||||
/// The header of a struct.
|
|
||||||
///
|
|
||||||
/// After this header are the fields of the struct, followed by `StructEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// struct S {
|
|
||||||
/// a: u8,
|
|
||||||
/// b: u8,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let s = S { a: 0, b: 0 };
|
|
||||||
/// assert_tokens(&s, &[
|
|
||||||
/// Token::Struct { name: "S", len: 2 },
|
|
||||||
/// Token::Str("a"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::Str("b"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::StructEnd,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
Struct { name: &'static str, len: usize },
|
|
||||||
|
|
||||||
/// An indicator of the end of a struct.
|
|
||||||
StructEnd,
|
|
||||||
|
|
||||||
/// The header of a struct variant of an enum.
|
|
||||||
///
|
|
||||||
/// After this header are the fields of the struct variant, followed by
|
|
||||||
/// `StructVariantEnd`.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// enum E {
|
|
||||||
/// D { d: u8 },
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let d = E::D { d: 0 };
|
|
||||||
/// assert_tokens(&d, &[
|
|
||||||
/// Token::StructVariant { name: "E", variant: "D", len: 1 },
|
|
||||||
/// Token::Str("d"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::StructVariantEnd,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
StructVariant {
|
|
||||||
name: &'static str,
|
|
||||||
variant: &'static str,
|
|
||||||
len: usize,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// An indicator of the end of a struct variant.
|
|
||||||
StructVariantEnd,
|
|
||||||
|
|
||||||
/// The header to an enum of the given name.
|
|
||||||
///
|
|
||||||
/// ```edition2018
|
|
||||||
/// # use serde::{Serialize, Deserialize};
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
|
||||||
/// enum E {
|
|
||||||
/// A,
|
|
||||||
/// B(u8),
|
|
||||||
/// C(u8, u8),
|
|
||||||
/// D { d: u8 },
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let a = E::A;
|
|
||||||
/// assert_tokens(&a, &[
|
|
||||||
/// Token::Enum { name: "E" },
|
|
||||||
/// Token::Str("A"),
|
|
||||||
/// Token::Unit,
|
|
||||||
/// ]);
|
|
||||||
///
|
|
||||||
/// let b = E::B(0);
|
|
||||||
/// assert_tokens(&b, &[
|
|
||||||
/// Token::Enum { name: "E" },
|
|
||||||
/// Token::Str("B"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// ]);
|
|
||||||
///
|
|
||||||
/// let c = E::C(0, 0);
|
|
||||||
/// assert_tokens(&c, &[
|
|
||||||
/// Token::Enum { name: "E" },
|
|
||||||
/// Token::Str("C"),
|
|
||||||
/// Token::Seq { len: Some(2) },
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::SeqEnd,
|
|
||||||
/// ]);
|
|
||||||
///
|
|
||||||
/// let d = E::D { d: 0 };
|
|
||||||
/// assert_tokens(&d, &[
|
|
||||||
/// Token::Enum { name: "E" },
|
|
||||||
/// Token::Str("D"),
|
|
||||||
/// Token::Map { len: Some(1) },
|
|
||||||
/// Token::Str("d"),
|
|
||||||
/// Token::U8(0),
|
|
||||||
/// Token::MapEnd,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
Enum { name: &'static str },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Token {
|
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
Debug::fmt(self, formatter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "serde_test_suite"
|
name = "serde_test_suite"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -12,10 +12,10 @@ unstable = ["serde/unstable"]
|
|||||||
serde = { path = "../serde" }
|
serde = { path = "../serde" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
automod = "1.0"
|
automod = "1.0.1"
|
||||||
fnv = "1.0"
|
foldhash = "0.2"
|
||||||
rustversion = "1.0"
|
rustversion = "1.0"
|
||||||
serde = { path = "../serde", features = ["rc", "derive"] }
|
serde = { path = "../serde", features = ["rc"] }
|
||||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||||
serde_test = { path = "../serde_test" }
|
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,11 +2,18 @@
|
|||||||
name = "serde_derive_tests_no_std"
|
name = "serde_derive_tests_no_std"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = { version = "0.2", default-features = false }
|
libc = { version = "0.2", default-features = false }
|
||||||
serde = { path = "../../serde", default-features = false, features = ["derive"] }
|
serde = { path = "../../serde", default-features = false }
|
||||||
|
serde_derive = { path = "../../serde_derive" }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#![feature(lang_items, start)]
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
#[start]
|
use core::ffi::c_int;
|
||||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "eh_personality"]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn rust_eh_personality() {}
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -19,24 +17,24 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Unit;
|
pub struct Unit;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Newtype(u8);
|
pub struct Newtype(u8);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Tuple(u8, u8);
|
pub struct Tuple(u8, u8);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Struct {
|
pub struct Struct {
|
||||||
f: u8,
|
f: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum Enum {
|
pub enum Enum {
|
||||||
Unit,
|
Unit,
|
||||||
Newtype(u8),
|
Newtype(u8),
|
||||||
Tuple(u8, u8),
|
Tuple(u8, u8),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
#[cfg_attr(target_os = "emscripten", ignore = "disabled on Emscripten")]
|
||||||
#[rustversion::attr(not(nightly), ignore)]
|
#[rustversion::attr(not(nightly), ignore = "requires nightly")]
|
||||||
#[cfg_attr(miri, ignore)]
|
#[cfg_attr(miri, ignore = "incompatible with miri")]
|
||||||
#[allow(unused_attributes)]
|
#[allow(unused_attributes)]
|
||||||
#[test]
|
#[test]
|
||||||
fn ui() {
|
fn ui() {
|
||||||
|
|||||||
@@ -34,9 +34,8 @@ macro_rules! hashset {
|
|||||||
$(set.insert($value);)+
|
$(set.insert($value);)+
|
||||||
set
|
set
|
||||||
}};
|
}};
|
||||||
($hasher:ident @ $($value:expr),+) => {{
|
($hasher:ty; $($value:expr),+) => {{
|
||||||
use std::hash::BuildHasherDefault;
|
let mut set = HashSet::<_, $hasher>::default();
|
||||||
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
|
|
||||||
$(set.insert($value);)+
|
$(set.insert($value);)+
|
||||||
set
|
set
|
||||||
}};
|
}};
|
||||||
@@ -51,9 +50,8 @@ macro_rules! hashmap {
|
|||||||
$(map.insert($key, $value);)+
|
$(map.insert($key, $value);)+
|
||||||
map
|
map
|
||||||
}};
|
}};
|
||||||
($hasher:ident @ $($key:expr => $value:expr),+) => {{
|
($hasher:ty; $($key:expr => $value:expr),+) => {{
|
||||||
use std::hash::BuildHasherDefault;
|
let mut map = HashMap::<_, _, $hasher>::default();
|
||||||
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
|
|
||||||
$(map.insert($key, $value);)+
|
$(map.insert($key, $value);)+
|
||||||
map
|
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,4 +1,6 @@
|
|||||||
use serde::Deserialize;
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Nested;
|
pub struct Nested;
|
||||||
@@ -7,7 +9,9 @@ pub struct Nested;
|
|||||||
pub enum ExternallyTagged {
|
pub enum ExternallyTagged {
|
||||||
Flatten {
|
Flatten {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
string: &'static str,
|
string: &'static str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -17,7 +21,9 @@ pub enum ExternallyTagged {
|
|||||||
pub enum InternallyTagged {
|
pub enum InternallyTagged {
|
||||||
Flatten {
|
Flatten {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
string: &'static str,
|
string: &'static str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -27,7 +33,9 @@ pub enum InternallyTagged {
|
|||||||
pub enum AdjacentlyTagged {
|
pub enum AdjacentlyTagged {
|
||||||
Flatten {
|
Flatten {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
string: &'static str,
|
string: &'static str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -37,7 +45,9 @@ pub enum AdjacentlyTagged {
|
|||||||
pub enum UntaggedWorkaround {
|
pub enum UntaggedWorkaround {
|
||||||
Flatten {
|
Flatten {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
nested: Nested,
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
string: &'static str,
|
string: &'static str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use serde::Deserialize;
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
macro_rules! bug {
|
macro_rules! bug {
|
||||||
($serde_path:literal) => {
|
($serde_path:literal) => {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ use serde_derive::Serialize;
|
|||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde()]
|
#[serde()]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct S;
|
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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
+1664
-1180
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user