mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-27 22:47:56 +00:00
Compare commits
1400 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 77a6a9d4e1 | |||
| 547d843cca | |||
| 005cb84593 | |||
| fd5b5e9aa5 | |||
| 0647a7c1fe | |||
| 85c73ef8de | |||
| 5ba1796a7e | |||
| e52b7b380f | |||
| 84c7419652 | |||
| 536221b1f9 | |||
| fc55ac70d3 | |||
| 2afe5b4ef9 | |||
| b4ec2595c9 | |||
| c3ac7b675a | |||
| 24614e44bf | |||
| 9b868ef831 | |||
| c3eaf76430 | |||
| 32958dec3b | |||
| d64a97ba1e | |||
| c3df3372a1 | |||
| 8764353fe2 | |||
| e08c5de5dd | |||
| bc5af506bd | |||
| 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 | |||
| dcbc3e0162 | |||
| 0289d31724 | |||
| 015e39776f | |||
| 6a9a21f178 | |||
| 81ac54b20d | |||
| 6b4e75520a | |||
| b053b4f492 | |||
| 4cf1fec575 | |||
| ee7d77defa | |||
| d0dfc4577e | |||
| bbbd1d24c9 | |||
| fb3a9e0d7c | |||
| 5ffebeb6ef | |||
| 75db73066b | |||
| 2796833c82 | |||
| 95730dc7f7 | |||
| 795261919f | |||
| 3783a30ae7 | |||
| b61ec84886 | |||
| 780a461d92 | |||
| c0ba323166 | |||
| 20a48c9580 | |||
| 09938803af | |||
| 6d0b43a220 | |||
| c604bdbfe4 | |||
| 9fef892f6d | |||
| b1c7db47b8 | |||
| e76e87a430 | |||
| 8a4dfa7231 | |||
| 107018c628 | |||
| a398237930 | |||
| b63c65d7f5 | |||
| f60324e883 | |||
| 361c23a09a | |||
| 43b23c7ea0 | |||
| 6081497506 | |||
| 48e5753e76 | |||
| bbba632ab3 | |||
| e77db40b8d | |||
| 2c1f62d4b4 | |||
| 1aebdc2760 | |||
| 705e58be8c | |||
| 7c2c12aa43 | |||
| a0f850f15b | |||
| fccb9499bc | |||
| a139ab2572 | |||
| 1d910a484c | |||
| ee9166ec97 | |||
| b5a9eff32e | |||
| 9441a29663 | |||
| ab6588ef74 | |||
| 1d11f03449 | |||
| e11d01fe1d | |||
| a901f50850 | |||
| c399e9c368 | |||
| 25381be0c9 | |||
| ef2a7c753f | |||
| 99f165b45a | |||
| 2fb5560746 | |||
| bd653ab30c | |||
| b5d68aedaa | |||
| 624879c4c6 | |||
| bd9e9abf35 | |||
| 3e4a23cbd0 | |||
| 6326ceec3f | |||
| 8f4d37c7ec | |||
| 1b8290b318 | |||
| 48193fbccd | |||
| 51799dd654 | |||
| 732ac49321 | |||
| ac8ea72d88 | |||
| f583401284 | |||
| 2d88228b7d | |||
| 0c6a2bbf79 | |||
| a80d830f27 | |||
| 5f3fd9994e | |||
| d6de911855 | |||
| 04af32230e | |||
| 4cb8d079f8 | |||
| 6ab55a1e52 | |||
| acfd19cb46 | |||
| e3058105f0 | |||
| dc200a6450 | |||
| 2c0999a0b9 | |||
| dd460f82a1 | |||
| c3d637f397 | |||
| 479a00a215 | |||
| c42e7c8012 | |||
| 5b8e0657d4 | |||
| 9fc0d13e2c | |||
| bc22641359 | |||
| 05098105a8 | |||
| 5b23634dc6 | |||
| 32f0d00ff9 | |||
| 9d87851f0c | |||
| c0296ee11b | |||
| 54671259aa | |||
| 994f7c7924 | |||
| 7a8e4977e2 | |||
| fb7b6ea7ea | |||
| 063dd5b93f | |||
| a38aa31ade | |||
| f42b2581da | |||
| 2ba406726f | |||
| 7e9826e17b | |||
| f4dcc5c918 | |||
| 8b1887c440 | |||
| bbfb1d3504 | |||
| e106feb5ec | |||
| 696f6f56db | |||
| b7b636a23f | |||
| 183b91775e | |||
| 0e70f59021 | |||
| 4d9b76db73 | |||
| 9af132f594 | |||
| 6c063569c0 | |||
| 7e9b98401d | |||
| f301e09e02 | |||
| b80e722f81 | |||
| 1714c262c4 | |||
| a42cdafdcd | |||
| eb4c3f16f7 | |||
| ce86f351d6 | |||
| 0b90f6c96a | |||
| 2198463218 | |||
| be57a5e00a | |||
| b1b09eba60 | |||
| eb1e8c140d | |||
| 43da87939d | |||
| 06d99a13a6 | |||
| 49a911d7de | |||
| 27d6628785 | |||
| e4e2956e79 | |||
| ea2f7b81d9 | |||
| f0dfdb5247 | |||
| 6a5da85fcd | |||
| 0750eee4ff | |||
| ef551a517c | |||
| 1c5ea24f76 | |||
| 88d73e5250 | |||
| 1ff2a972c6 | |||
| bb72fe2726 | |||
| e50b14afee | |||
| cbd1cbef07 | |||
| 01da3f79c9 | |||
| f5e0fbcb14 | |||
| 38c130a303 | |||
| c7393614ff | |||
| a13c6382b6 | |||
| a803ec1c1f | |||
| f7636428ed | |||
| f85c4f2fa9 | |||
| a9a9903107 | |||
| bd4a0981ba | |||
| 35e5cf3e15 | |||
| 07fc9f689e | |||
| 14b0e18c57 | |||
| dd27ec8703 | |||
| db3f00c3b3 | |||
| adcb11ca18 | |||
| b7be637e8c | |||
| 30c4aa2cf4 | |||
| a649190a4d | |||
| d81f0ef652 | |||
| 1a3a49ce7c | |||
| 6b948111ca | |||
| 6adfdc56e5 | |||
| 61531ddd9e | |||
| ccf9c6fc07 | |||
| b25d0ea7f9 | |||
| 4f4557fd05 | |||
| bf400d6799 | |||
| 4d2e36d19b | |||
| df6310e5f5 | |||
| 938ab5ddec | |||
| ef5a0de384 | |||
| 5d186c77a6 | |||
| 44bf3633af | |||
| f261184416 | |||
| df40f80fcf | |||
| e7060ba83d | |||
| d98f0eea3d | |||
| 4f157a8b81 | |||
| d493649f52 | |||
| 0e947e6c3b | |||
| 9249dab54c | |||
| 7440e56c53 | |||
| 0d79306285 | |||
| 37faaf295e | |||
| 650358fa00 | |||
| 6159ead404 | |||
| 692ac99c69 | |||
| 86161ce15f | |||
| 5361c790bb | |||
| 126730edc8 | |||
| 3aec2a96a8 | |||
| 227d039b1e | |||
| 0353354d61 | |||
| 34ae0422f4 | |||
| cc128feb4c | |||
| 7766103174 | |||
| 30f7c7110d | |||
| 50354c2d0b | |||
| c4f67e679f | |||
| 0daafe423f | |||
| 37021910c9 | |||
| 7328b34810 | |||
| fabbd2b097 | |||
| 6814f978d7 | |||
| 4ea403c54a | |||
| f4f6b5af3a | |||
| 2062a3c16d | |||
| 9a53bd9125 | |||
| 4873b48b02 | |||
| e19844c659 | |||
| 93bb9e147c | |||
| ab230e6e44 | |||
| 51ea34b217 | |||
| 1050f6b808 | |||
| 15ec95a98d | |||
| 072145e0e9 | |||
| 92957f17f2 | |||
| 667db558b6 | |||
| f41509261e | |||
| 6d009711a2 | |||
| 354b48fd40 | |||
| 3fd8e52f0c | |||
| 142dce0d3d | |||
| 6aed101630 | |||
| e2ccfd9ea7 | |||
| a07d794f74 | |||
| 90d28fc314 | |||
| 55cf0ac51a | |||
| 07696c1674 | |||
| f803b290f3 | |||
| d96e181150 | |||
| 3ffb86fc70 | |||
| 649a72a587 | |||
| b2676348eb | |||
| 8c036ee5a3 | |||
| d99009f3c6 | |||
| be3c37eb8b | |||
| f0346ae054 | |||
| fa6ce42056 | |||
| a9320db6f9 | |||
| d208762c81 | |||
| 5386897d24 | |||
| 68eb59df0c | |||
| a7f4551669 | |||
| 983347484e | |||
| f52d134c14 | |||
| 6660676b0d | |||
| 1d42d3571a | |||
| ebd06eebdb | |||
| f1985823a3 | |||
| 60e4092b8e | |||
| 3d0251666e | |||
| 7770da4929 | |||
| a5fd85a9ef | |||
| abb2a8494d | |||
| a31d0be191 | |||
| d786e750d7 | |||
| 10e4839f83 | |||
| 85e72653c8 | |||
| c9cc8a8924 | |||
| a925ce4119 | |||
| c5f6338ce2 | |||
| 5185487d73 | |||
| efaafd4458 | |||
| a0eb83a5d4 | |||
| 7cc6f7fbb0 | |||
| 44b9496c91 | |||
| 7e1486d0da | |||
| 8170ffef2e | |||
| 4b622f6bbf | |||
| 0ee71c70af | |||
| 6c098e497e | |||
| 41ffa6df7e | |||
| 845b900fd5 | |||
| 7891ae7184 | |||
| bac90d19b9 | |||
| 227bf3023a | |||
| f4535f68c1 | |||
| c6c35b5a31 | |||
| 31e51324e2 | |||
| bc3f24e0e9 | |||
| 2e38e2bf2f | |||
| 819f90d9f6 | |||
| 2eed86cd67 | |||
| 3921b57435 | |||
| 68069d734a | |||
| dc84693507 | |||
| 4cf012c5be | |||
| 17c3c0cf86 | |||
| 210e6c354e | |||
| 41823a96df | |||
| 7ca13ff240 | |||
| 52391fd868 | |||
| 9b2d8dfc6b | |||
| 07ba7ea8dd | |||
| 9f29f6bb4a | |||
| f6c104fd1d | |||
| 8a3a6fb101 | |||
| b5c3b5e8e5 | |||
| 996d171461 | |||
| e1c4517335 | |||
| 6e94a27c76 | |||
| b23a768414 | |||
| 7e19ae8c94 | |||
| 404a1d142a | |||
| 02bd79a0ba | |||
| c3ce2c934a | |||
| 0d71ac84b5 | |||
| 82c3eb7ba4 | |||
| 8932c852a5 | |||
| 9f3dd3c7c4 | |||
| dd9b415ff9 | |||
| 3bb4a5a4f6 | |||
| 6164627bea | |||
| 51aaf496d4 | |||
| bc66aeb0d3 | |||
| 7e7044d457 | |||
| 5498dc0550 | |||
| ff04e8be9b | |||
| 69240c17c5 | |||
| 237434f19c | |||
| 1833914346 | |||
| ab848060f2 | |||
| 7e39623f72 | |||
| 157dc44c51 | |||
| 80d01a3a79 | |||
| 343c060fc1 | |||
| 21c1ab6c50 | |||
| 594ab7745d | |||
| 8cf0ba7fe2 | |||
| 34b52c0b83 | |||
| ec7ddc93cd | |||
| 55a7cedd73 | |||
| 7af97c66b8 | |||
| 1f57084365 | |||
| 56bd369422 | |||
| ff259ec66b | |||
| 6c54aafeb9 | |||
| 5d41404e67 | |||
| 1eccb3c350 | |||
| 77ae1c3bf7 | |||
| b85e28166c | |||
| 0508cb50fc | |||
| 84fdc7df69 | |||
| ab1ca04b2e | |||
| fb2fe409c8 | |||
| 549fac7235 | |||
| c375d8b19b | |||
| 6cf507f808 | |||
| c3c1641c06 | |||
| 1fcda0ebdb | |||
| 8f16ac0a94 | |||
| 737f78c315 | |||
| 4a97386cb9 | |||
| 5b32217877 | |||
| 5b140361a3 | |||
| 678351eac7 | |||
| 999c261d11 | |||
| efbe574209 | |||
| 33b2677384 | |||
| 01ded9f405 | |||
| fc827ecec2 | |||
| 5c785eee58 | |||
| 819db93a3d | |||
| a6690ea2fe | |||
| 65e1a50749 | |||
| 87d41b59fd | |||
| 3f120fb355 | |||
| 2b92c80cc1 | |||
| c1c0ede452 | |||
| 4a66c5f33d | |||
| 714c8a5586 | |||
| dc0c0dcba1 | |||
| 54102ee7d0 | |||
| 14accf7518 | |||
| 55fdbea20b | |||
| 75d8902371 | |||
| 9451ea8df1 | |||
| c1ce03b3dd | |||
| a587eb8953 | |||
| 990f7eb6c1 | |||
| 082e18f9a1 | |||
| f309485787 | |||
| e2f85681fe | |||
| 8b840c3030 | |||
| 9c39115f82 | |||
| 89342af71e | |||
| 3c5e2d11f6 | |||
| 3805c037a8 | |||
| 7045fee260 | |||
| 9d81532e41 | |||
| 5e47432ef0 | |||
| e0fc46783d | |||
| ca772a14f9 | |||
| 7b840897a9 | |||
| 967795414b | |||
| 985725f820 | |||
| 0c303d85d7 | |||
| f68e9e901e | |||
| 1094e2d334 | |||
| d9c338ec4a | |||
| 699bf3a75d | |||
| dd29825217 | |||
| 6366f17da7 | |||
| 1120e5af4a | |||
| 1093f7e232 | |||
| 2ea132b8c4 | |||
| 2ebc771b88 | |||
| c17c4eef18 | |||
| 7aa4950504 | |||
| 47015a2727 | |||
| dc4c31eb50 | |||
| b53ebef438 | |||
| 6c3bf7a2fc | |||
| ce0844b9ec | |||
| e9270e59f0 | |||
| 72060b779a | |||
| 1bb23ad9d1 | |||
| 9be4c9654a | |||
| 4114e90bac | |||
| 8bb07b0743 | |||
| ba8c1d63c8 | |||
| 857a805993 | |||
| 5a8dcac2ed | |||
| 697b082e90 | |||
| d91075c8d5 | |||
| 4118cec731 | |||
| c261015325 | |||
| 6b5e5a83d0 | |||
| bc6b2b1dee | |||
| beb21cb640 | |||
| 7cfebbcd72 | |||
| b60c03ec3f | |||
| 3257851192 | |||
| 9a84622c56 | |||
| de8ac1c0be | |||
| 3d6c4149b1 | |||
| 29cdf888c0 | |||
| 2ba97394fb | |||
| 6699b0bc40 | |||
| b054ea4105 | |||
| e5efb6ad93 | |||
| 1f423580a5 | |||
| 033114a4ae | |||
| 7cec99c7fd | |||
| 6c5bf701be | |||
| 6e800ff826 | |||
| 68bda7a004 | |||
| dfeaf77bb2 | |||
| b0cc213e57 | |||
| 74ca06662e | |||
| 38edb473de | |||
| 1c03647656 | |||
| aeee73fe92 | |||
| 1a3ef39040 | |||
| deaf600af7 | |||
| 48556a4c7f | |||
| d88a4748f7 | |||
| ffed19243d | |||
| bb7f94df84 | |||
| ff0f467e25 | |||
| d1975f3661 | |||
| b91713e824 | |||
| 6ea446fb4b | |||
| 85c6904a93 | |||
| 2fd5212204 | |||
| 7d1bc1f0fc | |||
| cdc2fa1b9f | |||
| ac4001e590 | |||
| fbcb2230bb | |||
| 86c88bea12 | |||
| 82d0fe00fd | |||
| e61261e002 | |||
| 9fd56cd41c | |||
| e81f54fbc8 | |||
| c67017d466 | |||
| f6e7366b46 | |||
| 1f9f72bc48 | |||
| e24dbc418d | |||
| 18e5b03fd1 | |||
| 5aa163f27e | |||
| 3728d3c67a | |||
| 3f48ed36cc | |||
| b6a2d07f26 | |||
| 84ad76b2e5 | |||
| e6b6602a42 | |||
| 999b94d6ae | |||
| fa6712d2bf | |||
| 012ea8eb84 | |||
| 9add5812e2 | |||
| 5fd52100b6 | |||
| 6670a309ca | |||
| b7bad3a165 | |||
| 4e002ece07 | |||
| eaccae2c46 | |||
| 990a502c39 | |||
| 661206d885 | |||
| 51d4563ed1 | |||
| 7db0982e58 | |||
| ed04824f10 | |||
| 88ee470a1c | |||
| a5ecbdb4f4 | |||
| bd588db067 | |||
| 8f09aeacdd | |||
| 0b5c56b0db | |||
| 85de92e6f7 | |||
| c858a1fa77 | |||
| d02eb22557 | |||
| 034fe25d5b | |||
| 0a230e8598 | |||
| b20214d4a0 | |||
| 34f4b68f77 | |||
| 60e08f9545 | |||
| ba46f45dc5 | |||
| 44b9567e21 | |||
| b276849ce1 | |||
| 398fba9b1e | |||
| cd6697b0e4 | |||
| c162d51866 | |||
| 78a9dbc57e | |||
| 391d3ababf | |||
| 99d9151ce9 | |||
| 4c89cf89fd | |||
| b0c99ed761 | |||
| dd1f4b483e | |||
| 91bfa8f947 | |||
| 8847800ce2 | |||
| 3c9fa1ccdf | |||
| 3c29a8857f | |||
| a5da27e16d | |||
| e797431268 | |||
| 4a335f8933 | |||
| 84721920fd | |||
| 192c7819ee | |||
| ede40bdfaa | |||
| e3d871ff7b | |||
| 5cbc8439ea | |||
| 0e1c4093c8 | |||
| 0d5b6c180c | |||
| 97c350a95e | |||
| 920a77ad61 | |||
| a227a87865 | |||
| 7a7a182ab6 | |||
| 9e1f573f88 | |||
| 094f63b86a | |||
| 42fa79455e | |||
| 104ad9a7dd | |||
| 23c14e5f33 | |||
| e80571751d | |||
| 0737474640 | |||
| 34de1e00c8 | |||
| f6eb34a830 | |||
| 8084258a3e | |||
| fc3f104c4a | |||
| 4bec9ffd0f | |||
| e6d2322e68 | |||
| 2b504099e4 | |||
| db3074a40f | |||
| 2e821eab4b | |||
| be7d0e7eb2 | |||
| b539cb45d7 | |||
| a5490e20e1 | |||
| 45c45e87bf | |||
| 2e76f7013f | |||
| d35de19120 | |||
| e5b3507145 | |||
| 7ea7c2ceb9 | |||
| 2b5b15967e | |||
| 2ef60b62ac | |||
| e6f086d85e | |||
| bf76f50294 | |||
| ba07075590 | |||
| 26186bddd1 | |||
| 53b9871b17 | |||
| f8787c3ca8 | |||
| 3022064f84 | |||
| 9e140a2071 | |||
| 24e6acbfae | |||
| 29c5a50935 | |||
| c619b2a7c4 | |||
| 764ebd9b17 | |||
| 010444dfa4 | |||
| 9c6f0c3a0e | |||
| a9f8ea0a1e | |||
| 04faac962a | |||
| 7e5701ad2b | |||
| 1cd10a7d09 | |||
| d5e6436b28 | |||
| 8ff11dc234 | |||
| 6b3777b617 | |||
| 7350b58f5c | |||
| 7351e0e55a | |||
| b3ff7e43ef | |||
| a50e1c20e9 | |||
| 6980727d74 | |||
| bb1dedf04d | |||
| f3520e526b | |||
| e8fd2c85c3 | |||
| 97962d51e2 | |||
| 95b1a5d3d9 | |||
| 0856a2c101 | |||
| 9f331cc257 | |||
| ef16c815f6 | |||
| c45a809d5c | |||
| f7d06cae4c | |||
| 31fe82a215 | |||
| ef6ed1d1be | |||
| 9d1251548b | |||
| c20730ee39 | |||
| afd51ef0f4 | |||
| 3167f98689 | |||
| 078b171c1b | |||
| da8d6f678e | |||
| 548eb8f667 | |||
| 1fe39043ee | |||
| c2114491ca | |||
| 9f47c47cad | |||
| d6b39fd2c1 | |||
| 4d6d0ae539 | |||
| dda070f45c | |||
| b97a183e82 | |||
| 9433004307 | |||
| 9476838264 | |||
| 172edc4cf4 | |||
| 3c97e1b9a9 | |||
| a81968af3c | |||
| ea2789df0f | |||
| b7cfe33101 | |||
| 1b8ebf6b64 | |||
| 35ad468780 | |||
| 850a29beb1 | |||
| 16bf9871cd | |||
| 6182eceed1 | |||
| 99bc52f685 | |||
| 726ff5ed31 | |||
| f63acb52dc | |||
| 36a66873cc | |||
| 63809e69c7 | |||
| f44402e224 | |||
| 099fa25b86 | |||
| c120c4518b | |||
| 115c1b4830 | |||
| 23db3a41e7 | |||
| e2ff603587 | |||
| 19a11237b8 | |||
| 732544aed6 | |||
| 65dfa607c8 | |||
| 59104bbc24 | |||
| 38ad09aeb7 | |||
| 02631cef42 | |||
| f369707dc5 | |||
| e16e924c21 | |||
| 8b52ddd5b9 | |||
| 112f2040ea | |||
| cd836eb3ca | |||
| 2b4355724e | |||
| 5534bf4df1 | |||
| 60522937af | |||
| 29be721f79 | |||
| 0c4ffad9ec | |||
| 03addbae55 | |||
| 0bab6be124 | |||
| b6def5300a | |||
| 1b35c9e27e | |||
| d1564525ad | |||
| 645f672a55 | |||
| a135199ab1 | |||
| 2a9971a69d | |||
| e2ada0efef | |||
| 69653a762d | |||
| c33fb95127 | |||
| ec6ca6bf73 | |||
| 078e88b223 | |||
| 1894cb703f | |||
| 27c283ab53 | |||
| 142955b109 | |||
| a61cd0f236 | |||
| cb1632e957 | |||
| dbf1f9ab8f | |||
| 137ab48aff | |||
| fc43def8a3 | |||
| 2a351016ed | |||
| dfa321a1dd | |||
| 895eb2ba6c | |||
| cd365de70c | |||
| 7f799f3948 | |||
| 234fbfd7e3 | |||
| b9909cef3d | |||
| d540e72fc7 | |||
| 13d0899776 | |||
| 4fefa7a01d | |||
| 90486607a1 | |||
| 0b303c766c | |||
| c371563bfc | |||
| d17d8eb3ee | |||
| bcaebdb2b7 | |||
| 43a9f59c18 | |||
| ff70409215 | |||
| 97a98a7031 | |||
| 533fb9cc44 | |||
| 59b99d2d60 | |||
| c796daed7c | |||
| 6e2c385fa5 | |||
| 9a0e4e0176 | |||
| 640f8e0e82 | |||
| 4eb580790d | |||
| a2c83d754b | |||
| 6f946b20ec | |||
| 4dda90502a | |||
| dc6dbba47c | |||
| 2ceabad360 | |||
| a00aee1495 | |||
| 4e31c9984d | |||
| b8772a1e40 | |||
| 42990d8264 | |||
| cf31418555 | |||
| 5db72b8ad9 | |||
| fe8f8bcf7b | |||
| d4d737de8d | |||
| 52f6e96ee8 | |||
| 44fa7b0f6b | |||
| bda561df4e | |||
| 8955420baf | |||
| 21ee256911 | |||
| 4aba6fae78 | |||
| fe06bc2f88 | |||
| 8dfb4cd02f | |||
| d1ade37827 | |||
| 9de49241fb | |||
| b24d50160a | |||
| e46463e69f | |||
| a3157c9572 | |||
| 0d4722680a | |||
| 7ab12597bb | |||
| b86a46c83c | |||
| 187a0a3ec0 | |||
| 111c18dec3 | |||
| 7a2b137912 | |||
| 791b9fbe81 | |||
| 0fdc0257aa | |||
| b6a77c4413 | |||
| 33438850a6 | |||
| fcbb3d3783 | |||
| acc8640c1e | |||
| c083cfd65e | |||
| 4cea81f93f | |||
| 2d36be753a | |||
| 738d29eaa9 | |||
| b536fb67a4 | |||
| b10c23a950 | |||
| 85a5cf7cb1 | |||
| 192f5cd647 | |||
| 7dceee64fe | |||
| 8ad6ae71c6 | |||
| 3ea85a28cf | |||
| 273ecdb786 | |||
| de40eb7306 | |||
| b9c44073ce | |||
| d6e5947ad2 | |||
| 668651ee01 | |||
| fb1cacc10e | |||
| 735e56c26f | |||
| 97de3dccbb | |||
| 690467cbe2 | |||
| 71efd8ffda | |||
| 9bb196ae6e | |||
| ce75418e40 | |||
| 78c7f09e28 | |||
| e7269ac84e | |||
| 34866e20a8 | |||
| 3ae2bee272 | |||
| d0fb958e99 | |||
| b941c63a53 | |||
| cf70c3fb05 | |||
| f249e72162 | |||
| 92e0b62c6b | |||
| cf32a5b204 | |||
| 7b0e06c825 | |||
| 3158bf9093 | |||
| 01fade764c | |||
| 210c2419be | |||
| da05163d51 | |||
| f3e2bb5104 | |||
| 7a4c1086b5 | |||
| e89feb9635 | |||
| 5f72766c27 | |||
| 85ae57040d | |||
| d55a4a279f | |||
| bee9299693 | |||
| 9529fcec96 | |||
| bcec168e23 | |||
| 102a332616 | |||
| a280942f02 | |||
| 637dba5c2a | |||
| 24f292d081 | |||
| fa5c99e48a | |||
| 48f1a2c9b2 | |||
| 50ebbd63c6 | |||
| 4e5f63ff45 | |||
| de709e72a8 | |||
| 56d3c8f071 | |||
| ce89adecc1 | |||
| bc7a85063d | |||
| 0574f1e020 | |||
| f9fdd60e2e | |||
| 1c1eecabc0 | |||
| abd3fd004e | |||
| 15ee353488 | |||
| e75efbfd31 | |||
| 1c97a7ecb3 | |||
| fccd3e9fba | |||
| 4cb13b33e0 | |||
| 629802f2ab | |||
| afb1754528 | |||
| dbd67c6c89 | |||
| ed01bdb9dd | |||
| b54821d8ab | |||
| 89c6a79b6e | |||
| cd0412bddc | |||
| e42262f0f5 | |||
| 0a3eeab273 | |||
| e4e110e28f | |||
| 0726623389 | |||
| fd9d334d01 | |||
| 840eb14121 | |||
| 8fef196ee4 | |||
| 9c756f1ec0 | |||
| 4c29eea790 | |||
| 6dd2b4607f | |||
| 1e9ae88f53 | |||
| 5cc3902ab9 | |||
| c8e09e2d6d | |||
| e2a2ba116c | |||
| 0a9d24a218 | |||
| c222183669 | |||
| 140f9beee7 | |||
| 28ce892617 | |||
| 1e6d3ff99b | |||
| fba1b92cbf | |||
| ce1686379d | |||
| 79a20e9e33 | |||
| e9cd73f78e | |||
| 0be7f36d51 | |||
| 4c6cb6e359 | |||
| 82bde8d166 | |||
| 465392b618 | |||
| f3c6b9f05a | |||
| 2f1945eaf2 | |||
| b4d8a55b2a | |||
| 0e6ce8fa50 | |||
| a295c38ba3 | |||
| 295730ba1e | |||
| ac0d8f61c5 | |||
| b811588fa0 | |||
| 5fcdf0ff2b | |||
| 650b723da3 | |||
| 97920be33a | |||
| 58bbaa9e80 | |||
| 94f152730c | |||
| 535e3d4372 | |||
| 2ea43c8986 | |||
| 71fe2a5534 | |||
| f3ffcfd61e | |||
| bf27b28554 | |||
| 344602d27e | |||
| 64c483cf80 | |||
| 19091aacc7 | |||
| ef9028d798 | |||
| 1668cd19d3 | |||
| 134f268cee | |||
| c473633676 | |||
| 6a3a82007c | |||
| 1d6ef76cfb | |||
| c8e3959435 | |||
| 796f412a1e | |||
| fa854a2108 | |||
| 3a097ff2d2 | |||
| 8463bfc1e5 | |||
| 7a72b4c624 | |||
| 670c179417 | |||
| 1b1d868837 | |||
| d9704d02bb | |||
| 1349548367 | |||
| 18b1604fc8 | |||
| 0def7da5a8 | |||
| 4bb45c8252 | |||
| bb99b31eb0 | |||
| 84397183f3 | |||
| aeae265777 | |||
| a9c5df5da1 | |||
| 96576c4de9 | |||
| 9ec68e5829 | |||
| face857d5e | |||
| 85a1cc9b4f | |||
| 630501b93d | |||
| 8bbc2995ca | |||
| 7d3872df57 | |||
| 1ed228b92b | |||
| b605cd1bb9 | |||
| fea4e8e5b6 | |||
| 1df8b5785b | |||
| 981a75d7c9 | |||
| 11cc7014b3 | |||
| 0b667c88fa | |||
| 054ab1adaf | |||
| f1f8386f2e | |||
| ba8c3970b0 | |||
| 2f36b26a5c | |||
| 9b4edb3a1d | |||
| b8adc5ffa2 | |||
| bd90cafda7 | |||
| 6d43a08a1d | |||
| e71b8598ae | |||
| 95d0f437e3 | |||
| c95ee3968a | |||
| c22dd4ada5 | |||
| 727a40fc5a | |||
| ce84a5f1d3 | |||
| e6fda1c410 | |||
| 294dccc5be | |||
| da346a8878 | |||
| c5ccb995ad | |||
| 05ab569a80 | |||
| ab3f4971f0 | |||
| 47e238aa13 | |||
| e49b6c708b | |||
| eb7250792b | |||
| 7e5066b878 | |||
| 889e17816f | |||
| b1b9702daf | |||
| 32728d2f1d | |||
| 807a097387 | |||
| 794ee15386 | |||
| 2359417804 | |||
| 7950f3cdc5 | |||
| b87f8f35ee | |||
| 9e53405f43 | |||
| c6c1d8fa86 | |||
| 8aa5c2b45d | |||
| 414fd694c0 | |||
| 7e82809592 | |||
| 0dae5db30e | |||
| 5c24f0f0f3 | |||
| c2591e9b39 | |||
| 8ce0dee6da | |||
| 16daba8ea9 | |||
| 8b4074ee77 | |||
| 85fbd8793a | |||
| 65705e2091 | |||
| 385a385c62 |
@@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
name: Help or discussion
|
|
||||||
about: This is the right place
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule: [cron: "40 1 * * *"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -Dwarnings
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test suite
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- run: cd test_suite && cargo test --features unstable
|
||||||
|
|
||||||
|
windows:
|
||||||
|
name: Test suite (windows)
|
||||||
|
runs-on: windows-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
|
||||||
|
|
||||||
|
stable:
|
||||||
|
name: Rust ${{matrix.rust}}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
rust: [stable, beta]
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{matrix.rust}}
|
||||||
|
- run: cd serde && cargo build --features rc
|
||||||
|
- run: cd serde && cargo build --no-default-features
|
||||||
|
|
||||||
|
nightly:
|
||||||
|
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
|
||||||
|
runs-on: ${{matrix.os}}-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu, windows]
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- run: cd serde && cargo build
|
||||||
|
- run: cd serde && cargo build --no-default-features
|
||||||
|
- run: cd serde && cargo build --no-default-features --features alloc
|
||||||
|
- run: cd serde && cargo build --no-default-features --features rc,alloc
|
||||||
|
- run: cd serde && cargo build --no-default-features --features unstable
|
||||||
|
- run: cd serde && cargo test --features derive,rc,unstable
|
||||||
|
- run: cd test_suite/no_std && cargo build
|
||||||
|
if: matrix.os != 'windows'
|
||||||
|
- run: cd serde_derive && cargo check --tests
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: --cfg exhaustive ${{env.RUSTFLAGS}}
|
||||||
|
if: matrix.os != 'windows'
|
||||||
|
|
||||||
|
build:
|
||||||
|
name: Rust ${{matrix.rust}}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
rust: [1.31.0, 1.34.0]
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{matrix.rust}}
|
||||||
|
- run: sed -i '/"test_suite"/d' Cargo.toml
|
||||||
|
- run: cd serde && cargo build --features rc
|
||||||
|
- run: cd serde && cargo build --no-default-features
|
||||||
|
- run: cd serde && cargo build
|
||||||
|
|
||||||
|
derive:
|
||||||
|
name: Rust 1.56.0
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@1.56.0
|
||||||
|
- run: sed -i '/"test_suite"/d' Cargo.toml
|
||||||
|
- run: cd serde && cargo check --no-default-features
|
||||||
|
- run: cd serde && cargo check
|
||||||
|
- run: cd serde_derive && cargo check
|
||||||
|
|
||||||
|
alloc:
|
||||||
|
name: Rust 1.36.0
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@1.36.0
|
||||||
|
- run: sed -i '/"test_suite"/d' Cargo.toml
|
||||||
|
- run: cd serde && cargo build --no-default-features --features alloc
|
||||||
|
|
||||||
|
minimal:
|
||||||
|
name: Minimal versions
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- run: cargo generate-lockfile -Z minimal-versions
|
||||||
|
- run: cargo check --locked --workspace
|
||||||
|
|
||||||
|
doc:
|
||||||
|
name: Documentation
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
env:
|
||||||
|
RUSTDOCFLAGS: -Dwarnings
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- uses: dtolnay/install@cargo-docs-rs
|
||||||
|
- run: cargo docs-rs -p serde
|
||||||
|
- run: cargo docs-rs -p serde_derive
|
||||||
|
- run: cargo docs-rs -p serde_derive_internals
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@clippy
|
||||||
|
- run: cd serde && cargo clippy --features rc,unstable -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
- run: cd serde_derive && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
- run: cd serde_derive_internals && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
- run: cd test_suite && cargo clippy --tests --features unstable -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
- run: cd test_suite/no_std && cargo clippy -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
|
||||||
|
miri:
|
||||||
|
name: Miri
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@miri
|
||||||
|
- run: cargo miri setup
|
||||||
|
- run: cd serde && cargo miri test --features derive,rc,unstable
|
||||||
|
env:
|
||||||
|
MIRIFLAGS: -Zmiri-strict-provenance
|
||||||
|
- run: cd test_suite && cargo miri test --features unstable
|
||||||
|
env:
|
||||||
|
MIRIFLAGS: -Zmiri-strict-provenance
|
||||||
|
|
||||||
|
outdated:
|
||||||
|
name: Outdated
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: dtolnay/install@cargo-outdated
|
||||||
|
- run: cargo outdated --workspace --exit-code 1
|
||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
language: rust
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- rust: stable
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo build --features rc
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde_test"
|
|
||||||
- cargo build
|
|
||||||
- cargo test
|
|
||||||
|
|
||||||
- rust: beta
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo build --features rc
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite"
|
|
||||||
- cargo test
|
|
||||||
|
|
||||||
- rust: nightly
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo build
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cargo build --no-default-features --features alloc
|
|
||||||
- cargo build --no-default-features --features rc,alloc
|
|
||||||
- cargo test --features rc,unstable
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite/deps"
|
|
||||||
- cargo build
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite"
|
|
||||||
- cargo test --features unstable
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite/no_std"
|
|
||||||
- cargo build
|
|
||||||
|
|
||||||
- rust: 1.13.0
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo build --features rc
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde_test"
|
|
||||||
- cargo build
|
|
||||||
|
|
||||||
- rust: 1.15.0
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
|
|
||||||
- cargo build
|
|
||||||
|
|
||||||
- rust: 1.20.0
|
|
||||||
- rust: 1.21.0
|
|
||||||
- rust: 1.25.0
|
|
||||||
- rust: 1.26.0
|
|
||||||
|
|
||||||
- rust: nightly
|
|
||||||
name: Clippy
|
|
||||||
script:
|
|
||||||
- rustup component add clippy-preview || travis_terminate 0
|
|
||||||
- cargo clippy -- -Dclippy
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo clippy --features rc,unstable -- -Dclippy
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde_derive"
|
|
||||||
- cargo clippy -- -Dclippy
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde_test"
|
|
||||||
- cargo clippy -- -Dclippy
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite"
|
|
||||||
- cargo clippy --features unstable -- -Dclippy
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite/no_std"
|
|
||||||
- cargo clippy -- -Dclippy
|
|
||||||
|
|
||||||
- rust: nightly
|
|
||||||
name: Emscripten
|
|
||||||
script:
|
|
||||||
- CARGO_WEB_RELEASE=$(curl -L -s -H Accept:application/json https://github.com/koute/cargo-web/releases/latest)
|
|
||||||
- CARGO_WEB_VERSION=$(echo "${CARGO_WEB_RELEASE}" | jq -r .tag_name)
|
|
||||||
- CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/${CARGO_WEB_VERSION}/cargo-web-x86_64-unknown-linux-gnu.gz"
|
|
||||||
|
|
||||||
- nvm install 9
|
|
||||||
- mkdir -p ~/.cargo/bin
|
|
||||||
- curl -L "${CARGO_WEB_URL}" | gzip -d > ~/.cargo/bin/cargo-web
|
|
||||||
- chmod +x ~/.cargo/bin/cargo-web
|
|
||||||
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/test_suite"
|
|
||||||
- cargo web test --target=asmjs-unknown-emscripten --nodejs
|
|
||||||
- cargo web test --target=wasm32-unknown-emscripten --nodejs
|
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
- rust: nightly
|
|
||||||
name: Clippy
|
|
||||||
- rust: nightly
|
|
||||||
name: Emscripten
|
|
||||||
|
|
||||||
script:
|
|
||||||
- cd "${TRAVIS_BUILD_DIR}/serde"
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cargo build
|
|
||||||
+5
-16
@@ -4,11 +4,6 @@ Serde welcomes contribution from everyone in the form of suggestions, bug
|
|||||||
reports, pull requests, and feedback. This document gives some guidance if you
|
reports, pull requests, and feedback. This document gives some guidance if you
|
||||||
are thinking of helping us.
|
are thinking of helping us.
|
||||||
|
|
||||||
Please reach out here in a GitHub issue or in the #serde IRC channel on
|
|
||||||
[`irc.mozilla.org`] if we can do anything to help you contribute.
|
|
||||||
|
|
||||||
[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
|
|
||||||
|
|
||||||
## Submitting bug reports and feature requests
|
## Submitting bug reports and feature requests
|
||||||
|
|
||||||
Serde development is spread across lots of repositories, but this serde-rs/serde
|
Serde development is spread across lots of repositories, but this serde-rs/serde
|
||||||
@@ -36,25 +31,19 @@ tests for you.
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Test all the example code in Serde documentation
|
# Test all the example code in Serde documentation
|
||||||
cargo test
|
cargo test --features derive
|
||||||
```
|
|
||||||
|
|
||||||
##### In the [`test_suite/deps`] directory
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# This is a prerequisite for running the full test suite
|
|
||||||
cargo clean && cargo update && cargo build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
##### In the [`test_suite`] directory
|
##### In the [`test_suite`] directory
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Run the full test suite, including tests of unstable functionality
|
# Run the full test suite, including tests of unstable functionality
|
||||||
cargo test --features unstable
|
cargo +nightly test --features unstable
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that this test suite currently only supports running on a nightly compiler.
|
||||||
|
|
||||||
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
|
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
|
||||||
[`test_suite/deps`]: https://github.com/serde-rs/serde/tree/master/test_suite/deps
|
|
||||||
[`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
|
||||||
@@ -63,4 +52,4 @@ In all Serde-related forums, we follow the [Rust Code of Conduct]. For
|
|||||||
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
||||||
instead of the Rust moderation team.
|
instead of the Rust moderation team.
|
||||||
|
|
||||||
[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html
|
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||||
|
|||||||
+8
-1
@@ -3,6 +3,13 @@ members = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_derive_internals",
|
"serde_derive_internals",
|
||||||
"serde_test",
|
|
||||||
"test_suite",
|
"test_suite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
serde = { path = "serde" }
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
proc-macro2 = { version = "1.0.74", default-features = false }
|
||||||
|
quote = { version = "1.0.35", default-features = false }
|
||||||
|
syn = { version = "2.0.46", default-features = false }
|
||||||
|
|||||||
@@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|||||||
of your accepting any such warranty or additional liability.
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc]
|
# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde msrv]][Rust 1.31] [![serde_derive msrv]][Rust 1.56]
|
||||||
|
|
||||||
[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master
|
[Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master
|
||||||
[travis]: https://travis-ci.org/serde-rs/serde
|
[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
|
||||||
[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg
|
[serde msrv]: https://img.shields.io/crates/msrv/serde.svg?label=serde%20msrv&color=lightgray
|
||||||
[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html
|
[serde_derive msrv]: https://img.shields.io/crates/msrv/serde_derive.svg?label=serde_derive%20msrv&color=lightgray
|
||||||
|
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
|
||||||
|
[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.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.**
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ You may be looking for:
|
|||||||
- [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)
|
||||||
- [API documentation](https://docs.serde.rs/serde/)
|
- [API documentation](https://docs.rs/serde)
|
||||||
- [Release notes](https://github.com/serde-rs/serde/releases)
|
- [Release notes](https://github.com/serde-rs/serde/releases)
|
||||||
|
|
||||||
## Serde in action
|
## Serde in action
|
||||||
@@ -25,19 +27,17 @@ 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/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
# The core APIs, including the Serialize and Deserialize traits. Always
|
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||||
# required when using Serde.
|
# required when using Serde. The "derive" feature is only required when
|
||||||
serde = "1.0"
|
# using #[derive(Serialize, Deserialize)] to make Serde work with structs
|
||||||
|
# and enums defined in your crate.
|
||||||
# Support for #[derive(Serialize, Deserialize)]. Required if you want Serde
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
# to work for structs and enums defined in your crate.
|
|
||||||
serde_derive = "1.0"
|
|
||||||
|
|
||||||
# Each data format lives in its own crate; the sample code below uses JSON
|
# Each data format lives in its own crate; the sample code below uses JSON
|
||||||
# but you may be using a different one.
|
# but you may be using a different one.
|
||||||
@@ -48,11 +48,7 @@ serde_json = "1.0"
|
|||||||
<p></p>
|
<p></p>
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
use serde::{Deserialize, Serialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
@@ -79,27 +75,40 @@ fn main() {
|
|||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
|
|
||||||
Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The
|
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
||||||
\#rust channel is also a good resource with generally faster response time but
|
congregate will be able to help you out. For chat, consider trying the
|
||||||
less specific knowledge about Serde. If IRC is not your thing or you don't get a
|
[#rust-questions] or [#rust-beginners] channels of the unofficial community
|
||||||
good response, we are happy to respond to [GitHub issues][issues] as well.
|
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage] or
|
||||||
|
[#beginners] channels of the official Rust Project Discord (invite:
|
||||||
|
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
|
||||||
|
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
|
||||||
|
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
|
||||||
|
[Discourse forum][discourse]. It's acceptable to file a support issue in this
|
||||||
|
repo but they tend not to get as many eyes as any of the above and may get
|
||||||
|
closed without a response after some time.
|
||||||
|
|
||||||
[irc]: https://wiki.mozilla.org/IRC
|
[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513
|
||||||
[issues]: https://github.com/serde-rs/serde/issues/new/choose
|
[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281
|
||||||
|
[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848
|
||||||
|
[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612
|
||||||
|
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general
|
||||||
|
[stackoverflow]: https://stackoverflow.com/questions/tagged/rust
|
||||||
|
[/r/rust]: https://www.reddit.com/r/rust
|
||||||
|
[discourse]: https://users.rust-lang.org
|
||||||
|
|
||||||
## License
|
<br>
|
||||||
|
|
||||||
Serde is licensed under either of
|
#### License
|
||||||
|
|
||||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
<sup>
|
||||||
http://www.apache.org/licenses/LICENSE-2.0)
|
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
|
||||||
http://opensource.org/licenses/MIT)
|
</sup>
|
||||||
|
|
||||||
at your option.
|
<br>
|
||||||
|
|
||||||
### Contribution
|
|
||||||
|
|
||||||
|
<sub>
|
||||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
|
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
|
||||||
dual licensed as above, without any additional terms or conditions.
|
dual licensed as above, without any additional terms or conditions.
|
||||||
|
</sub>
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- APPVEYOR_RUST_CHANNEL: stable
|
|
||||||
- APPVEYOR_RUST_CHANNEL: nightly
|
|
||||||
|
|
||||||
install:
|
|
||||||
# Install rust, x86_64-pc-windows-msvc host
|
|
||||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
|
||||||
- rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain %APPVEYOR_RUST_CHANNEL%
|
|
||||||
- set PATH=C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin
|
|
||||||
- rustc -vV
|
|
||||||
- cargo -vV
|
|
||||||
|
|
||||||
build: false
|
|
||||||
|
|
||||||
for:
|
|
||||||
- matrix:
|
|
||||||
only:
|
|
||||||
- APPVEYOR_RUST_CHANNEL: stable
|
|
||||||
test_script:
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%\serde
|
|
||||||
- cargo build --features rc
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%\serde_test
|
|
||||||
- cargo build
|
|
||||||
- cargo test
|
|
||||||
|
|
||||||
- matrix:
|
|
||||||
only:
|
|
||||||
- APPVEYOR_RUST_CHANNEL: nightly
|
|
||||||
test_script:
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%\serde
|
|
||||||
- cargo build
|
|
||||||
- cargo build --no-default-features
|
|
||||||
- cargo build --no-default-features --features alloc
|
|
||||||
- cargo build --no-default-features --features rc,alloc
|
|
||||||
- cargo test --features rc,unstable
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%\test_suite\deps
|
|
||||||
- cargo build
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%\test_suite
|
|
||||||
- cargo test --features unstable
|
|
||||||
+21
-12
@@ -10,17 +10,13 @@ You may be looking for:
|
|||||||
- [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)
|
||||||
- [API documentation](https://docs.serde.rs/serde/)
|
- [API documentation](https://docs.rs/serde)
|
||||||
- [Release notes](https://github.com/serde-rs/serde/releases)
|
- [Release notes](https://github.com/serde-rs/serde/releases)
|
||||||
|
|
||||||
## Serde in action
|
## Serde in action
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
use serde::{Deserialize, Serialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Point {
|
struct Point {
|
||||||
@@ -47,10 +43,23 @@ fn main() {
|
|||||||
|
|
||||||
## Getting help
|
## Getting help
|
||||||
|
|
||||||
Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The
|
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
||||||
\#rust channel is also a good resource with generally faster response time but
|
congregate will be able to help you out. For chat, consider trying the
|
||||||
less specific knowledge about Serde. If IRC is not your thing or you don't get a
|
[#rust-questions] or [#rust-beginners] channels of the unofficial community
|
||||||
good response, we are happy to respond to [GitHub issues][issues] as well.
|
Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage]
|
||||||
|
or [#beginners] channels of the official Rust Project Discord (invite:
|
||||||
|
<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For
|
||||||
|
asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the
|
||||||
|
[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust
|
||||||
|
[Discourse forum][discourse]. It's acceptable to file a support issue in this
|
||||||
|
repo but they tend not to get as many eyes as any of the above and may get
|
||||||
|
closed without a response after some time.
|
||||||
|
|
||||||
[irc]: https://wiki.mozilla.org/IRC
|
[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513
|
||||||
[issues]: https://github.com/serde-rs/serde/issues/new/choose
|
[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281
|
||||||
|
[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848
|
||||||
|
[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612
|
||||||
|
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general
|
||||||
|
[stackoverflow]: https://stackoverflow.com/questions/tagged/rust
|
||||||
|
[/r/rust]: https://www.reddit.com/r/rust
|
||||||
|
[discourse]: https://users.rust-lang.org
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
error_on_line_overflow = false
|
|
||||||
+34
-45
@@ -1,27 +1,43 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.81" # remember to update html_root_url
|
version = "1.0.209"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
description = "A generic serialization/deserialization framework"
|
|
||||||
homepage = "https://serde.rs"
|
|
||||||
repository = "https://github.com/serde-rs/serde"
|
|
||||||
documentation = "https://docs.serde.rs/serde/"
|
|
||||||
keywords = ["serde", "serialization", "no_std"]
|
|
||||||
categories = ["encoding"]
|
|
||||||
readme = "crates-io.md"
|
|
||||||
include = ["Cargo.toml", "build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||||
[badges]
|
description = "A generic serialization/deserialization framework"
|
||||||
travis-ci = { repository = "serde-rs/serde" }
|
documentation = "https://docs.rs/serde"
|
||||||
appveyor = { repository = "serde-rs/serde" }
|
edition = "2018"
|
||||||
|
homepage = "https://serde.rs"
|
||||||
|
keywords = ["serde", "serialization", "no_std"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
readme = "crates-io.md"
|
||||||
|
repository = "https://github.com/serde-rs/serde"
|
||||||
|
rust-version = "1.31"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_derive = { version = "1.0", optional = true, path = "../serde_derive" }
|
serde_derive = { version = "1", optional = true, path = "../serde_derive" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
serde_derive = { version = "1", path = "../serde_derive" }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[package.metadata.playground]
|
||||||
|
features = ["derive", "rc"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["derive", "rc", "unstable"]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
rustdoc-args = ["--generate-link-to-definition"]
|
||||||
|
|
||||||
|
# This cfg cannot be enabled, but it still forces Cargo to keep serde_derive's
|
||||||
|
# version in lockstep with serde's, even if someone depends on the two crates
|
||||||
|
# separately with serde's "derive" feature disabled. Every serde_derive release
|
||||||
|
# is compatible with exactly one serde release because the generated code
|
||||||
|
# involves nonpublic APIs which are not bound by semver.
|
||||||
|
[target.'cfg(any())'.dependencies]
|
||||||
|
serde_derive = { version = "=1.0.209", path = "../serde_derive" }
|
||||||
|
|
||||||
|
|
||||||
### FEATURES #################################################################
|
### FEATURES #################################################################
|
||||||
@@ -29,30 +45,7 @@ serde_derive = { version = "1.0", path = "../serde_derive" }
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|
||||||
# Re-export the derive(Serialize, Deserialize) macros. This is intended for
|
# Provide derive(Serialize, Deserialize) macros.
|
||||||
# library crates that provide optional Serde impls behind a Cargo cfg of their
|
|
||||||
# own.
|
|
||||||
#
|
|
||||||
# Mainly this is a workaround for limitations associated with
|
|
||||||
# rust-lang/cargo#1286 in which a library crate cannot use one "serde" cfg in
|
|
||||||
# Cargo to enable dependencies on both serde and serde_derive crates.
|
|
||||||
#
|
|
||||||
# The recommended way to provide optional Serde support that requires derive is
|
|
||||||
# as follows. In particular, please do not name your library's Serde feature
|
|
||||||
# anything other than "serde".
|
|
||||||
#
|
|
||||||
# [dependencies]
|
|
||||||
# serde = { version = "1.0", optional = true, features = ["derive"] }
|
|
||||||
#
|
|
||||||
# Within the library, these optional Serde derives would be written like this.
|
|
||||||
#
|
|
||||||
# #[cfg(feature = "serde")]
|
|
||||||
# #[macro_use]
|
|
||||||
# extern crate serde;
|
|
||||||
#
|
|
||||||
# #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
# struct ...
|
|
||||||
#
|
|
||||||
derive = ["serde_derive"]
|
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>.
|
||||||
@@ -68,11 +61,7 @@ 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 = []
|
||||||
# Requires a dependency on the unstable core allocation library:
|
|
||||||
#
|
|
||||||
# https://doc.rust-lang.org/alloc/
|
|
||||||
alloc = ["unstable"]
|
|
||||||
|
|
||||||
# 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.
|
||||||
|
|||||||
+66
-28
@@ -6,52 +6,90 @@ use std::str::{self, FromStr};
|
|||||||
// 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
|
||||||
// these cfgs other than by executing our build script.
|
// these cfgs other than by executing our build script.
|
||||||
fn main() {
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
let minor = match rustc_minor_version() {
|
let minor = match rustc_minor_version() {
|
||||||
Some(minor) => minor,
|
Some(minor) => minor,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if minor >= 77 {
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_core_cstr)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_core_num_saturating)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_core_try_from)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_diagnostic_namespace)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_float_copysign)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_num_nonzero_signed)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_relaxed_trait_bounds)");
|
||||||
|
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_systemtime_checked_add)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(no_target_has_atomic)");
|
||||||
|
}
|
||||||
|
|
||||||
let target = env::var("TARGET").unwrap();
|
let target = env::var("TARGET").unwrap();
|
||||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
||||||
|
|
||||||
// CString::into_boxed_c_str stabilized in Rust 1.20:
|
// TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
|
||||||
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
|
// stabilized in Rust 1.34:
|
||||||
if minor >= 20 {
|
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
|
||||||
println!("cargo:rustc-cfg=de_boxed_c_str");
|
// 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
|
// f32::copysign and f64::copysign stabilized in Rust 1.35.
|
||||||
// https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
|
// https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html#copy-the-sign-of-a-floating-point-number-onto-another
|
||||||
// https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
|
if minor < 35 {
|
||||||
if minor >= 21 {
|
println!("cargo:rustc-cfg=no_float_copysign");
|
||||||
println!("cargo:rustc-cfg=de_rc_dst");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duration available in core since Rust 1.25:
|
// Current minimum supported version of serde_derive crate is Rust 1.56.
|
||||||
// https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations
|
if minor < 56 {
|
||||||
if minor >= 25 {
|
println!("cargo:rustc-cfg=no_serde_derive");
|
||||||
println!("cargo:rustc-cfg=core_duration");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 128-bit integers stabilized in Rust 1.26:
|
// Support for #[cfg(target_has_atomic = "...")] stabilized in Rust 1.60.
|
||||||
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
|
if minor < 60 {
|
||||||
//
|
println!("cargo:rustc-cfg=no_target_has_atomic");
|
||||||
// Disabled on Emscripten targets as Emscripten doesn't
|
// Allowlist of archs that support std::sync::atomic module. This is
|
||||||
// currently support integers larger than 64 bits.
|
// based on rustc's compiler/rustc_target/src/spec/*.rs.
|
||||||
if minor >= 26 && !emscripten {
|
let has_atomic64 = target.starts_with("x86_64")
|
||||||
println!("cargo:rustc-cfg=integer128");
|
|| 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inclusive ranges methods stabilized in Rust 1.27:
|
// Support for core::ffi::CStr and alloc::ffi::CString stabilized in Rust 1.64.
|
||||||
// https://github.com/rust-lang/rust/pull/50758
|
// https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#c-compatible-ffi-types-in-core-and-alloc
|
||||||
if minor >= 27 {
|
if minor < 64 {
|
||||||
println!("cargo:rustc-cfg=range_inclusive");
|
println!("cargo:rustc-cfg=no_core_cstr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-zero integers stabilized in Rust 1.28:
|
// Support for core::num::Saturating and std::num::Saturating stabilized in Rust 1.74
|
||||||
// https://github.com/rust-lang/rust/pull/50808
|
// https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html#stabilized-apis
|
||||||
if minor >= 28 {
|
if minor < 74 {
|
||||||
println!("cargo:rustc-cfg=num_nonzero");
|
println!("cargo:rustc-cfg=no_core_num_saturating");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
use crate::lib::fmt::{self, Write};
|
||||||
|
use crate::lib::str;
|
||||||
|
|
||||||
|
pub(super) struct Buf<'a> {
|
||||||
|
bytes: &'a mut [u8],
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Buf<'a> {
|
||||||
|
pub fn new(bytes: &'a mut [u8]) -> Self {
|
||||||
|
Buf { bytes, offset: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
let slice = &self.bytes[..self.offset];
|
||||||
|
unsafe { str::from_utf8_unchecked(slice) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Write for Buf<'a> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
if self.offset + s.len() > self.bytes.len() {
|
||||||
|
Err(fmt::Error)
|
||||||
|
} else {
|
||||||
|
self.bytes[self.offset..self.offset + s.len()].copy_from_slice(s.as_bytes());
|
||||||
|
self.offset += s.len();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
use lib::*;
|
|
||||||
|
|
||||||
macro_rules! int_to_int {
|
|
||||||
($dst:ident, $n:ident) => {
|
|
||||||
if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 {
|
|
||||||
Some($n as $dst)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! int_to_uint {
|
|
||||||
($dst:ident, $n:ident) => {
|
|
||||||
if 0 <= $n && $n as u64 <= $dst::max_value() as u64 {
|
|
||||||
Some($n as $dst)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! uint_to {
|
|
||||||
($dst:ident, $n:ident) => {
|
|
||||||
if $n as u64 <= $dst::max_value() as u64 {
|
|
||||||
Some($n as $dst)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FromPrimitive: Sized {
|
|
||||||
fn from_i8(n: i8) -> Option<Self>;
|
|
||||||
fn from_i16(n: i16) -> Option<Self>;
|
|
||||||
fn from_i32(n: i32) -> Option<Self>;
|
|
||||||
fn from_i64(n: i64) -> Option<Self>;
|
|
||||||
fn from_u8(n: u8) -> Option<Self>;
|
|
||||||
fn from_u16(n: u16) -> Option<Self>;
|
|
||||||
fn from_u32(n: u32) -> Option<Self>;
|
|
||||||
fn from_u64(n: u64) -> Option<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_primitive_for_int {
|
|
||||||
($t:ident) => {
|
|
||||||
impl FromPrimitive for $t {
|
|
||||||
#[inline]
|
|
||||||
fn from_i8(n: i8) -> Option<Self> {
|
|
||||||
int_to_int!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i16(n: i16) -> Option<Self> {
|
|
||||||
int_to_int!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i32(n: i32) -> Option<Self> {
|
|
||||||
int_to_int!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i64(n: i64) -> Option<Self> {
|
|
||||||
int_to_int!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u8(n: u8) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u16(n: u16) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(n: u32) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u64(n: u64) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_primitive_for_uint {
|
|
||||||
($t:ident) => {
|
|
||||||
impl FromPrimitive for $t {
|
|
||||||
#[inline]
|
|
||||||
fn from_i8(n: i8) -> Option<Self> {
|
|
||||||
int_to_uint!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i16(n: i16) -> Option<Self> {
|
|
||||||
int_to_uint!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i32(n: i32) -> Option<Self> {
|
|
||||||
int_to_uint!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i64(n: i64) -> Option<Self> {
|
|
||||||
int_to_uint!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u8(n: u8) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u16(n: u16) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(n: u32) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u64(n: u64) -> Option<Self> {
|
|
||||||
uint_to!($t, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_from_primitive_for_float {
|
|
||||||
($t:ident) => {
|
|
||||||
impl FromPrimitive for $t {
|
|
||||||
#[inline]
|
|
||||||
fn from_i8(n: i8) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i16(n: i16) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i32(n: i32) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i64(n: i64) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u8(n: u8) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u16(n: u16) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(n: u32) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u64(n: u64) -> Option<Self> {
|
|
||||||
Some(n as Self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_primitive_for_int!(isize);
|
|
||||||
impl_from_primitive_for_int!(i8);
|
|
||||||
impl_from_primitive_for_int!(i16);
|
|
||||||
impl_from_primitive_for_int!(i32);
|
|
||||||
impl_from_primitive_for_int!(i64);
|
|
||||||
impl_from_primitive_for_uint!(usize);
|
|
||||||
impl_from_primitive_for_uint!(u8);
|
|
||||||
impl_from_primitive_for_uint!(u16);
|
|
||||||
impl_from_primitive_for_uint!(u32);
|
|
||||||
impl_from_primitive_for_uint!(u64);
|
|
||||||
impl_from_primitive_for_float!(f32);
|
|
||||||
impl_from_primitive_for_float!(f64);
|
|
||||||
|
|
||||||
serde_if_integer128! {
|
|
||||||
impl FromPrimitive for i128 {
|
|
||||||
#[inline]
|
|
||||||
fn from_i8(n: i8) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i16(n: i16) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i32(n: i32) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i64(n: i64) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u8(n: u8) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u16(n: u16) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(n: u32) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u64(n: u64) -> Option<Self> {
|
|
||||||
Some(n as i128)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromPrimitive for u128 {
|
|
||||||
#[inline]
|
|
||||||
fn from_i8(n: i8) -> Option<Self> {
|
|
||||||
if n >= 0 {
|
|
||||||
Some(n as u128)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i16(n: i16) -> Option<Self> {
|
|
||||||
if n >= 0 {
|
|
||||||
Some(n as u128)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i32(n: i32) -> Option<Self> {
|
|
||||||
if n >= 0 {
|
|
||||||
Some(n as u128)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_i64(n: i64) -> Option<Self> {
|
|
||||||
if n >= 0 {
|
|
||||||
Some(n as u128)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u8(n: u8) -> Option<Self> {
|
|
||||||
Some(n as u128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u16(n: u16) -> Option<Self> {
|
|
||||||
Some(n as u128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(n: u32) -> Option<Self> {
|
|
||||||
Some(n as u128)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_u64(n: u64) -> Option<Self> {
|
|
||||||
Some(n as u128)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+30
-10
@@ -1,6 +1,8 @@
|
|||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
use crate::de::{
|
||||||
|
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
|
||||||
|
};
|
||||||
|
|
||||||
/// An efficient way of discarding data from a deserializer.
|
/// An efficient way of discarding data from a deserializer.
|
||||||
///
|
///
|
||||||
@@ -8,20 +10,19 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
|||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```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`.
|
||||||
/// ///
|
/// ///
|
||||||
/// /// For example to deserialize only the element at index 3:
|
/// /// For example to deserialize only the element at index 3:
|
||||||
/// ///
|
/// ///
|
||||||
/// /// ```rust
|
/// /// ```
|
||||||
/// /// NthElement::new(3).deserialize(deserializer)
|
/// /// NthElement::new(3).deserialize(deserializer)
|
||||||
/// /// ```
|
/// /// ```
|
||||||
/// pub struct NthElement<T> {
|
/// pub struct NthElement<T> {
|
||||||
@@ -106,7 +107,7 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
|||||||
/// # 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 {
|
||||||
@@ -128,12 +129,24 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||||
|
let _ = x;
|
||||||
|
Ok(IgnoredAny)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
|
fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
|
||||||
let _ = x;
|
let _ = x;
|
||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||||
|
let _ = x;
|
||||||
|
Ok(IgnoredAny)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
|
fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
|
||||||
let _ = x;
|
let _ = x;
|
||||||
@@ -180,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)
|
||||||
@@ -191,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)
|
||||||
@@ -205,6 +218,13 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
|||||||
let _ = bytes;
|
let _ = bytes;
|
||||||
Ok(IgnoredAny)
|
Ok(IgnoredAny)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: EnumAccess<'de>,
|
||||||
|
{
|
||||||
|
tri!(data.variant::<IgnoredAny>()).1.newtype_variant()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for IgnoredAny {
|
impl<'de> Deserialize<'de> for IgnoredAny {
|
||||||
|
|||||||
+1283
-519
File diff suppressed because it is too large
Load Diff
+210
-140
@@ -30,7 +30,7 @@
|
|||||||
//! # The Deserializer trait
|
//! # The Deserializer trait
|
||||||
//!
|
//!
|
||||||
//! [`Deserializer`] implementations are provided by third-party crates, for
|
//! [`Deserializer`] implementations are provided by third-party crates, for
|
||||||
//! example [`serde_json`], [`serde_yaml`] and [`bincode`].
|
//! example [`serde_json`], [`serde_yaml`] and [`postcard`].
|
||||||
//!
|
//!
|
||||||
//! A partial list of well-maintained formats is given on the [Serde
|
//! A partial list of well-maintained formats is given on the [Serde
|
||||||
//! website][data formats].
|
//! website][data formats].
|
||||||
@@ -59,13 +59,13 @@
|
|||||||
//! - Box\<T\>
|
//! - Box\<T\>
|
||||||
//! - Box\<\[T\]\>
|
//! - Box\<\[T\]\>
|
||||||
//! - Box\<str\>
|
//! - Box\<str\>
|
||||||
//! - Rc\<T\>
|
|
||||||
//! - Arc\<T\>
|
|
||||||
//! - Cow\<'a, T\>
|
//! - Cow\<'a, T\>
|
||||||
//! - Cell\<T\>
|
//! - Cell\<T\>
|
||||||
//! - RefCell\<T\>
|
//! - RefCell\<T\>
|
||||||
//! - Mutex\<T\>
|
//! - Mutex\<T\>
|
||||||
//! - RwLock\<T\>
|
//! - RwLock\<T\>
|
||||||
|
//! - Rc\<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\>
|
||||||
@@ -89,6 +89,7 @@
|
|||||||
//! - PathBuf
|
//! - PathBuf
|
||||||
//! - Range\<T\>
|
//! - Range\<T\>
|
||||||
//! - RangeInclusive\<T\>
|
//! - RangeInclusive\<T\>
|
||||||
|
//! - Bound\<T\>
|
||||||
//! - num::NonZero*
|
//! - num::NonZero*
|
||||||
//! - `!` *(unstable)*
|
//! - `!` *(unstable)*
|
||||||
//! - **Net types**:
|
//! - **Net types**:
|
||||||
@@ -103,7 +104,7 @@
|
|||||||
//! [`Deserialize`]: ../trait.Deserialize.html
|
//! [`Deserialize`]: ../trait.Deserialize.html
|
||||||
//! [`Deserializer`]: ../trait.Deserializer.html
|
//! [`Deserializer`]: ../trait.Deserializer.html
|
||||||
//! [`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
|
||||||
//! [`bincode`]: https://github.com/TyOverby/bincode
|
//! [`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
|
||||||
//! [`serde_derive`]: https://crates.io/crates/serde_derive
|
//! [`serde_derive`]: https://crates.io/crates/serde_derive
|
||||||
//! [`serde_json`]: https://github.com/serde-rs/json
|
//! [`serde_json`]: https://github.com/serde-rs/json
|
||||||
@@ -111,19 +112,29 @@
|
|||||||
//! [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;
|
||||||
|
|
||||||
mod from_primitive;
|
mod format;
|
||||||
mod ignored_any;
|
mod ignored_any;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod utf8;
|
pub(crate) mod size_hint;
|
||||||
|
|
||||||
pub use self::ignored_any::IgnoredAny;
|
pub use self::ignored_any::IgnoredAny;
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use crate::std_error::Error as StdError;
|
||||||
|
#[cfg(all(feature = "unstable", not(feature = "std")))]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use core::error::Error as StdError;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use std::error::Error as StdError;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! declare_error_trait {
|
macro_rules! declare_error_trait {
|
||||||
@@ -153,7 +164,7 @@ macro_rules! declare_error_trait {
|
|||||||
///
|
///
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// #
|
/// #
|
||||||
/// # struct IpAddr;
|
/// # struct IpAddr;
|
||||||
@@ -173,7 +184,7 @@ macro_rules! declare_error_trait {
|
|||||||
/// where
|
/// where
|
||||||
/// D: Deserializer<'de>,
|
/// D: Deserializer<'de>,
|
||||||
/// {
|
/// {
|
||||||
/// let s = try!(String::deserialize(deserializer));
|
/// let s = String::deserialize(deserializer)?;
|
||||||
/// s.parse().map_err(de::Error::custom)
|
/// s.parse().map_err(de::Error::custom)
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
@@ -237,12 +248,16 @@ macro_rules! declare_error_trait {
|
|||||||
#[cold]
|
#[cold]
|
||||||
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
|
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
|
||||||
if expected.is_empty() {
|
if expected.is_empty() {
|
||||||
Error::custom(format_args!("unknown variant `{}`, there are no variants",
|
Error::custom(format_args!(
|
||||||
variant))
|
"unknown variant `{}`, there are no variants",
|
||||||
|
variant
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Error::custom(format_args!("unknown variant `{}`, expected {}",
|
Error::custom(format_args!(
|
||||||
variant,
|
"unknown variant `{}`, expected {}",
|
||||||
OneOf { names: expected }))
|
variant,
|
||||||
|
OneOf { names: expected }
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,12 +266,16 @@ macro_rules! declare_error_trait {
|
|||||||
#[cold]
|
#[cold]
|
||||||
fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
|
fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
|
||||||
if expected.is_empty() {
|
if expected.is_empty() {
|
||||||
Error::custom(format_args!("unknown field `{}`, there are no fields",
|
Error::custom(format_args!(
|
||||||
field))
|
"unknown field `{}`, there are no fields",
|
||||||
|
field
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Error::custom(format_args!("unknown field `{}`, expected {}",
|
Error::custom(format_args!(
|
||||||
field,
|
"unknown field `{}`, expected {}",
|
||||||
OneOf { names: expected }))
|
field,
|
||||||
|
OneOf { names: expected }
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +298,7 @@ macro_rules! declare_error_trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
declare_error_trait!(Error: Sized + error::Error);
|
declare_error_trait!(Error: Sized + StdError);
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
declare_error_trait!(Error: Sized + Debug + Display);
|
declare_error_trait!(Error: Sized + Debug + Display);
|
||||||
@@ -290,7 +309,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # use serde::de::{self, Unexpected, Visitor};
|
/// # use serde::de::{self, Unexpected, Visitor};
|
||||||
@@ -377,26 +396,26 @@ pub enum Unexpected<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for Unexpected<'a> {
|
impl<'a> fmt::Display for Unexpected<'a> {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::Unexpected::*;
|
use self::Unexpected::*;
|
||||||
match *self {
|
match *self {
|
||||||
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,10 +434,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
|
||||||
/// #
|
|
||||||
/// # use serde::de::{self, Unexpected, Visitor};
|
/// # use serde::de::{self, Unexpected, Visitor};
|
||||||
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # struct Example;
|
/// # struct Example;
|
||||||
/// #
|
/// #
|
||||||
@@ -440,7 +458,7 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
|||||||
///
|
///
|
||||||
/// Outside of a `Visitor`, `&"..."` can be used.
|
/// Outside of a `Visitor`, `&"..."` can be used.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, Unexpected};
|
/// # use serde::de::{self, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # fn example<E>() -> Result<(), E>
|
/// # fn example<E>() -> Result<(), E>
|
||||||
@@ -448,7 +466,10 @@ 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",
|
||||||
|
/// ));
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Expected {
|
pub trait Expected {
|
||||||
@@ -484,8 +505,8 @@ impl<'a> Display for Expected + 'a {
|
|||||||
/// by Serde.
|
/// by Serde.
|
||||||
///
|
///
|
||||||
/// Serde provides `Deserialize` implementations for many Rust primitive and
|
/// Serde provides `Deserialize` implementations for many Rust primitive and
|
||||||
/// standard library types. The complete list is [here][de]. All of these can
|
/// standard library types. The complete list is [here][crate::de]. All of these
|
||||||
/// be deserialized using Serde out of the box.
|
/// can be deserialized using Serde out of the box.
|
||||||
///
|
///
|
||||||
/// Additionally, Serde provides a procedural macro called `serde_derive` to
|
/// Additionally, Serde provides a procedural macro called `serde_derive` to
|
||||||
/// automatically generate `Deserialize` implementations for structs and enums
|
/// automatically generate `Deserialize` implementations for structs and enums
|
||||||
@@ -501,7 +522,6 @@ impl<'a> Display for Expected + 'a {
|
|||||||
/// `LinkedHashMap<K, V>` type that is deserializable by Serde because the crate
|
/// `LinkedHashMap<K, V>` type that is deserializable by Serde because the crate
|
||||||
/// provides an implementation of `Deserialize` for it.
|
/// provides an implementation of `Deserialize` for it.
|
||||||
///
|
///
|
||||||
/// [de]: https://docs.serde.rs/serde/de/index.html
|
|
||||||
/// [derive]: https://serde.rs/derive.html
|
/// [derive]: https://serde.rs/derive.html
|
||||||
/// [impl-deserialize]: https://serde.rs/impl-deserialize.html
|
/// [impl-deserialize]: https://serde.rs/impl-deserialize.html
|
||||||
///
|
///
|
||||||
@@ -512,6 +532,13 @@ 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(
|
||||||
|
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.
|
||||||
///
|
///
|
||||||
@@ -548,7 +575,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 = Deserialize::deserialize(deserializer)?;
|
*place = tri!(Deserialize::deserialize(deserializer));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,7 +588,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{Deserialize, DeserializeOwned};
|
/// # use serde::de::{Deserialize, DeserializeOwned};
|
||||||
/// # use std::io::{Read, Result};
|
/// # use std::io::{Read, Result};
|
||||||
/// #
|
/// #
|
||||||
@@ -600,7 +627,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::Deserialize;
|
/// # use serde::Deserialize;
|
||||||
/// #
|
/// #
|
||||||
/// # enum Error {}
|
/// # enum Error {}
|
||||||
@@ -614,7 +641,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::DeserializeSeed;
|
/// # use serde::de::DeserializeSeed;
|
||||||
/// #
|
/// #
|
||||||
/// # enum Error {}
|
/// # enum Error {}
|
||||||
@@ -647,12 +674,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```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
|
||||||
@@ -691,6 +717,11 @@ impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
|||||||
/// where
|
/// where
|
||||||
/// A: SeqAccess<'de>,
|
/// A: SeqAccess<'de>,
|
||||||
/// {
|
/// {
|
||||||
|
/// // Decrease the number of reallocations if there are many elements
|
||||||
|
/// if let Some(size_hint) = seq.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
|
||||||
/// // the existing vector.
|
/// // the existing vector.
|
||||||
/// while let Some(elem) = seq.next_element()? {
|
/// while let Some(elem) = seq.next_element()? {
|
||||||
@@ -778,7 +809,7 @@ where
|
|||||||
///
|
///
|
||||||
/// The role of this trait is to define the deserialization half of the [Serde
|
/// The role of this trait is to define the deserialization half of the [Serde
|
||||||
/// data model], which is a way to categorize every Rust data type into one of
|
/// data model], which is a way to categorize every Rust data type into one of
|
||||||
/// 29 possible types. Each method of the `Serializer` trait corresponds to one
|
/// 29 possible types. Each method of the `Deserializer` trait corresponds to one
|
||||||
/// of the types of the data model.
|
/// of the types of the data model.
|
||||||
///
|
///
|
||||||
/// Implementations of `Deserialize` map themselves into this data model by
|
/// Implementations of `Deserialize` map themselves into this data model by
|
||||||
@@ -840,10 +871,10 @@ where
|
|||||||
/// The `Deserializer` trait supports two entry point styles which enables
|
/// The `Deserializer` trait supports two entry point styles which enables
|
||||||
/// different kinds of deserialization.
|
/// different kinds of deserialization.
|
||||||
///
|
///
|
||||||
/// 1. The `deserialize` method. Self-describing data formats like JSON are able
|
/// 1. The `deserialize_any` method. Self-describing data formats like JSON are
|
||||||
/// to look at the serialized data and tell what it represents. For example
|
/// able to look at the serialized data and tell what it represents. For
|
||||||
/// the JSON deserializer may see an opening curly brace (`{`) and know that
|
/// example the JSON deserializer may see an opening curly brace (`{`) and
|
||||||
/// it is seeing a map. If the data format supports
|
/// know that it is seeing a map. If the data format supports
|
||||||
/// `Deserializer::deserialize_any`, it will drive the Visitor using whatever
|
/// `Deserializer::deserialize_any`, it will drive the Visitor using whatever
|
||||||
/// type it sees in the input. JSON uses this approach when deserializing
|
/// type it sees in the input. JSON uses this approach when deserializing
|
||||||
/// `serde_json::Value` which is an enum that can represent any JSON
|
/// `serde_json::Value` which is an enum that can represent any JSON
|
||||||
@@ -852,7 +883,7 @@ where
|
|||||||
/// `Deserializer::deserialize_any`.
|
/// `Deserializer::deserialize_any`.
|
||||||
///
|
///
|
||||||
/// 2. The various `deserialize_*` methods. Non-self-describing formats like
|
/// 2. The various `deserialize_*` methods. Non-self-describing formats like
|
||||||
/// Bincode need to be told what is in the input in order to deserialize it.
|
/// Postcard need to be told what is in the input in order to deserialize it.
|
||||||
/// The `deserialize_*` methods are hints to the deserializer for how to
|
/// The `deserialize_*` methods are hints to the deserializer for how to
|
||||||
/// interpret the next piece of input. Non-self-describing formats are not
|
/// interpret the next piece of input. Non-self-describing formats are not
|
||||||
/// able to deserialize something like `serde_json::Value` which relies on
|
/// able to deserialize something like `serde_json::Value` which relies on
|
||||||
@@ -862,7 +893,7 @@ where
|
|||||||
/// `Deserializer::deserialize_any` unless you need to be told by the
|
/// `Deserializer::deserialize_any` unless you need to be told by the
|
||||||
/// Deserializer what type is in the input. Know that relying on
|
/// Deserializer what type is in the input. Know that relying on
|
||||||
/// `Deserializer::deserialize_any` means your data type will be able to
|
/// `Deserializer::deserialize_any` means your data type will be able to
|
||||||
/// deserialize from self-describing formats only, ruling out Bincode and many
|
/// deserialize from self-describing formats only, ruling out Postcard and many
|
||||||
/// others.
|
/// others.
|
||||||
///
|
///
|
||||||
/// [Serde data model]: https://serde.rs/data-model.html
|
/// [Serde data model]: https://serde.rs/data-model.html
|
||||||
@@ -893,7 +924,7 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
/// `Deserializer::deserialize_any` unless you need to be told by the
|
/// `Deserializer::deserialize_any` unless you need to be told by the
|
||||||
/// Deserializer what type is in the input. Know that relying on
|
/// Deserializer what type is in the input. Know that relying on
|
||||||
/// `Deserializer::deserialize_any` means your data type will be able to
|
/// `Deserializer::deserialize_any` means your data type will be able to
|
||||||
/// deserialize from self-describing formats only, ruling out Bincode and
|
/// deserialize from self-describing formats only, ruling out Postcard and
|
||||||
/// many others.
|
/// many others.
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
@@ -924,18 +955,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.
|
||||||
@@ -958,18 +986,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.
|
||||||
@@ -992,7 +1017,7 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
/// `Deserializer`.
|
/// `Deserializer`.
|
||||||
///
|
///
|
||||||
/// If the `Visitor` would benefit from taking ownership of `String` data,
|
/// If the `Visitor` would benefit from taking ownership of `String` data,
|
||||||
/// indiciate this to the `Deserializer` by using `deserialize_string`
|
/// indicate this to the `Deserializer` by using `deserialize_string`
|
||||||
/// instead.
|
/// instead.
|
||||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
@@ -1134,10 +1159,10 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
/// Some types have a human-readable form that may be somewhat expensive to
|
/// Some types have a human-readable form that may be somewhat expensive to
|
||||||
/// construct, as well as a binary form that is compact and efficient.
|
/// construct, as well as a binary form that is compact and efficient.
|
||||||
/// Generally text-based formats like JSON and YAML will prefer to use the
|
/// Generally text-based formats like JSON and YAML will prefer to use the
|
||||||
/// human-readable one and binary formats like Bincode will prefer the
|
/// human-readable one and binary formats like Postcard will prefer the
|
||||||
/// compact one.
|
/// compact one.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```edition2021
|
||||||
/// # use std::ops::Add;
|
/// # use std::ops::Add;
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// #
|
/// #
|
||||||
@@ -1198,6 +1223,20 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
fn is_human_readable(&self) -> bool {
|
fn is_human_readable(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not public API.
|
||||||
|
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn __deserialize_content<V>(
|
||||||
|
self,
|
||||||
|
_: crate::actually_private::T,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<crate::__private::de::Content<'de>, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de, Value = crate::__private::de::Content<'de>>,
|
||||||
|
{
|
||||||
|
self.deserialize_any(visitor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1214,10 +1253,9 @@ pub trait Deserializer<'de>: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```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.
|
||||||
@@ -1255,7 +1293,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use std::fmt;
|
/// # use std::fmt;
|
||||||
/// #
|
/// #
|
||||||
/// # struct S {
|
/// # struct S {
|
||||||
@@ -1328,18 +1366,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 = format::Buf::new(&mut buf);
|
||||||
let _ = v;
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as i128", v)).unwrap();
|
||||||
Err(Error::invalid_type(Unexpected::Other("i128"), &self))
|
Err(Error::invalid_type(
|
||||||
}
|
Unexpected::Other(writer.as_str()),
|
||||||
|
&self,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains a `u8`.
|
/// The input contains a `u8`.
|
||||||
@@ -1388,18 +1428,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 = format::Buf::new(&mut buf);
|
||||||
let _ = v;
|
fmt::Write::write_fmt(&mut writer, format_args!("integer `{}` as u128", v)).unwrap();
|
||||||
Err(Error::invalid_type(Unexpected::Other("u128"), &self))
|
Err(Error::invalid_type(
|
||||||
}
|
Unexpected::Other(writer.as_str()),
|
||||||
|
&self,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The input contains an `f32`.
|
/// The input contains an `f32`.
|
||||||
@@ -1435,7 +1477,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
|
||||||
@@ -1490,6 +1532,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,
|
||||||
@@ -1512,7 +1555,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))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1520,7 +1562,7 @@ pub trait Visitor<'de>: Sized {
|
|||||||
/// `Deserializer`.
|
/// `Deserializer`.
|
||||||
///
|
///
|
||||||
/// This enables zero-copy deserialization of bytes in some formats. For
|
/// This enables zero-copy deserialization of bytes in some formats. For
|
||||||
/// example Bincode data containing bytes can be deserialized with zero
|
/// example Postcard data containing bytes can be deserialized with zero
|
||||||
/// copying into a `&'a [u8]` as long as the input data outlives `'a`.
|
/// copying into a `&'a [u8]` as long as the input data outlives `'a`.
|
||||||
///
|
///
|
||||||
/// The default implementation forwards to `visit_bytes`.
|
/// The default implementation forwards to `visit_bytes`.
|
||||||
@@ -1549,6 +1591,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,
|
||||||
@@ -1701,7 +1744,7 @@ pub trait SeqAccess<'de> {
|
|||||||
|
|
||||||
impl<'de, 'a, A> SeqAccess<'de> for &'a mut A
|
impl<'de, 'a, A> SeqAccess<'de> for &'a mut A
|
||||||
where
|
where
|
||||||
A: SeqAccess<'de>,
|
A: ?Sized + SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
type Error = A::Error;
|
type Error = A::Error;
|
||||||
|
|
||||||
@@ -1792,9 +1835,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),
|
||||||
@@ -1854,7 +1897,7 @@ pub trait MapAccess<'de> {
|
|||||||
|
|
||||||
impl<'de, 'a, A> MapAccess<'de> for &'a mut A
|
impl<'de, 'a, A> MapAccess<'de> for &'a mut A
|
||||||
where
|
where
|
||||||
A: MapAccess<'de>,
|
A: ?Sized + MapAccess<'de>,
|
||||||
{
|
{
|
||||||
type Error = A::Error;
|
type Error = A::Error;
|
||||||
|
|
||||||
@@ -1996,7 +2039,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2036,7 +2079,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2092,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2109,11 +2152,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>,
|
||||||
/// {
|
/// {
|
||||||
@@ -2139,7 +2178,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:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||||
/// #
|
/// #
|
||||||
/// # struct X;
|
/// # struct X;
|
||||||
@@ -2199,14 +2238,10 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// #[macro_use]
|
|
||||||
/// extern crate serde_derive;
|
|
||||||
///
|
|
||||||
/// extern crate serde;
|
|
||||||
///
|
|
||||||
/// use std::str::FromStr;
|
|
||||||
/// use serde::de::{value, Deserialize, IntoDeserializer};
|
/// use serde::de::{value, Deserialize, IntoDeserializer};
|
||||||
|
/// use serde_derive::Deserialize;
|
||||||
|
/// use std::str::FromStr;
|
||||||
///
|
///
|
||||||
/// #[derive(Deserialize)]
|
/// #[derive(Deserialize)]
|
||||||
/// enum Setting {
|
/// enum Setting {
|
||||||
@@ -2221,8 +2256,6 @@ pub trait VariantAccess<'de>: Sized {
|
|||||||
/// Self::deserialize(s.into_deserializer())
|
/// Self::deserialize(s.into_deserializer())
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
pub trait IntoDeserializer<'de, E: Error = value::Error> {
|
pub trait IntoDeserializer<'de, E: Error = value::Error> {
|
||||||
/// The type of the deserializer being converted into.
|
/// The type of the deserializer being converted into.
|
||||||
@@ -2252,15 +2285,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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use crate::de::{Deserialize, DeserializeSeed, Deserializer};
|
||||||
|
|
||||||
|
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
|
||||||
|
///
|
||||||
|
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
||||||
|
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
|
||||||
|
|
||||||
|
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
type Value = ();
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
T::deserialize_in_place(deserializer, self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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: buf, pos: 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+407
-74
@@ -1,14 +1,10 @@
|
|||||||
//! Building blocks for deserializing basic values using the `IntoDeserializer`
|
//! Building blocks for deserializing basic values using the `IntoDeserializer`
|
||||||
//! trait.
|
//! trait.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```edition2021
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate serde_derive;
|
|
||||||
//!
|
|
||||||
//! extern crate serde;
|
|
||||||
//!
|
|
||||||
//! use std::str::FromStr;
|
|
||||||
//! use serde::de::{value, Deserialize, IntoDeserializer};
|
//! use serde::de::{value, Deserialize, IntoDeserializer};
|
||||||
|
//! use serde_derive::Deserialize;
|
||||||
|
//! use std::str::FromStr;
|
||||||
//!
|
//!
|
||||||
//! #[derive(Deserialize)]
|
//! #[derive(Deserialize)]
|
||||||
//! enum Setting {
|
//! enum Setting {
|
||||||
@@ -23,16 +19,13 @@
|
|||||||
//! Self::deserialize(s.into_deserializer())
|
//! Self::deserialize(s.into_deserializer())
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! #
|
|
||||||
//! # fn main() {}
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use self::private::{First, Second};
|
use self::private::{First, Second};
|
||||||
use de::{self, Expected, IntoDeserializer, SeqAccess};
|
use crate::de::{self, size_hint, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||||
use private::de::size_hint;
|
use crate::ser;
|
||||||
use ser;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -54,7 +47,7 @@ macro_rules! impl_copy_clone {
|
|||||||
|
|
||||||
/// A minimal representation of all possible errors that can occur using the
|
/// A minimal representation of all possible errors that can occur using the
|
||||||
/// `IntoDeserializer` trait.
|
/// `IntoDeserializer` trait.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
err: ErrorImpl,
|
err: ErrorImpl,
|
||||||
}
|
}
|
||||||
@@ -99,17 +92,27 @@ impl ser::Error for Error {
|
|||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str(&self.err)
|
formatter.write_str(&self.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("Serde deserialization error")
|
formatter.write_str("Serde deserialization error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Error {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut debug = formatter.debug_tuple("Error");
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
debug.field(&self.err);
|
||||||
|
debug.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[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
|
||||||
@@ -125,20 +128,26 @@ where
|
|||||||
type Deserializer = UnitDeserializer<E>;
|
type Deserializer = UnitDeserializer<E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> UnitDeserializer<E> {
|
fn into_deserializer(self) -> UnitDeserializer<E> {
|
||||||
UnitDeserializer {
|
UnitDeserializer::new()
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A deserializer holding a `()`.
|
/// A deserializer holding a `()`.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UnitDeserializer<E> {
|
pub struct UnitDeserializer<E> {
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_copy_clone!(UnitDeserializer);
|
impl_copy_clone!(UnitDeserializer);
|
||||||
|
|
||||||
|
impl<E> UnitDeserializer<E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
UnitDeserializer {
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de, E> de::Deserializer<'de> for UnitDeserializer<E>
|
impl<'de, E> de::Deserializer<'de> for UnitDeserializer<E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
@@ -166,16 +175,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E> Debug for UnitDeserializer<E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.debug_struct("UnitDeserializer").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// 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,
|
||||||
@@ -214,7 +231,6 @@ macro_rules! primitive_deserializer {
|
|||||||
($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => {
|
($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => {
|
||||||
#[doc = "A deserializer holding"]
|
#[doc = "A deserializer holding"]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct $name<E> {
|
pub struct $name<E> {
|
||||||
value: $ty,
|
value: $ty,
|
||||||
marker: PhantomData<E>
|
marker: PhantomData<E>
|
||||||
@@ -229,8 +245,15 @@ macro_rules! primitive_deserializer {
|
|||||||
type Deserializer = $name<E>;
|
type Deserializer = $name<E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> $name<E> {
|
fn into_deserializer(self) -> $name<E> {
|
||||||
|
$name::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> $name<E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new(value: $ty) -> Self {
|
||||||
$name {
|
$name {
|
||||||
value: self,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,6 +278,15 @@ macro_rules! primitive_deserializer {
|
|||||||
visitor.$method(self.value $($cast)*)
|
visitor.$method(self.value $($cast)*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E> Debug for $name<E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct(stringify!($name))
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,22 +295,18 @@ 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`.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct U32Deserializer<E> {
|
pub struct U32Deserializer<E> {
|
||||||
value: u32,
|
value: u32,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -293,8 +321,15 @@ where
|
|||||||
type Deserializer = U32Deserializer<E>;
|
type Deserializer = U32Deserializer<E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> U32Deserializer<E> {
|
fn into_deserializer(self) -> U32Deserializer<E> {
|
||||||
|
U32Deserializer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> U32Deserializer<E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new(value: u32) -> Self {
|
||||||
U32Deserializer {
|
U32Deserializer {
|
||||||
value: self,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,10 +384,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E> Debug for U32Deserializer<E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("U32Deserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer holding a `&str`.
|
/// A deserializer holding a `&str`.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StrDeserializer<'a, E> {
|
pub struct StrDeserializer<'a, E> {
|
||||||
value: &'a str,
|
value: &'a str,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -367,8 +410,15 @@ where
|
|||||||
type Deserializer = StrDeserializer<'a, E>;
|
type Deserializer = StrDeserializer<'a, E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> StrDeserializer<'a, E> {
|
fn into_deserializer(self) -> StrDeserializer<'a, E> {
|
||||||
|
StrDeserializer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E> StrDeserializer<'a, E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new(value: &'a str) -> Self {
|
||||||
StrDeserializer {
|
StrDeserializer {
|
||||||
value: self,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,11 +473,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, E> Debug for StrDeserializer<'a, E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("StrDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer holding a `&str` with a lifetime tied to another
|
/// A deserializer holding a `&str` with a lifetime tied to another
|
||||||
/// deserializer.
|
/// deserializer.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BorrowedStrDeserializer<'de, E> {
|
pub struct BorrowedStrDeserializer<'de, E> {
|
||||||
value: &'de str,
|
value: &'de str,
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
@@ -439,7 +497,7 @@ impl<'de, E> BorrowedStrDeserializer<'de, E> {
|
|||||||
/// Create a new borrowed deserializer from the given string.
|
/// Create a new borrowed deserializer from the given string.
|
||||||
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
|
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
|
||||||
BorrowedStrDeserializer {
|
BorrowedStrDeserializer {
|
||||||
value: value,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,11 +552,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de, E> Debug for BorrowedStrDeserializer<'de, E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("BorrowedStrDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer holding a `String`.
|
/// A deserializer holding a `String`.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
#[derive(Debug)]
|
#[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>,
|
||||||
@@ -515,6 +582,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,
|
||||||
@@ -522,8 +590,16 @@ where
|
|||||||
type Deserializer = StringDeserializer<E>;
|
type Deserializer = StringDeserializer<E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> StringDeserializer<E> {
|
fn into_deserializer(self) -> StringDeserializer<E> {
|
||||||
|
StringDeserializer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<E> StringDeserializer<E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new(value: String) -> Self {
|
||||||
StringDeserializer {
|
StringDeserializer {
|
||||||
value: self,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,7 +641,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<'de, 'a, E> de::EnumAccess<'de> for StringDeserializer<E>
|
impl<'de, E> de::EnumAccess<'de> for StringDeserializer<E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
@@ -580,11 +656,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<E> Debug for StringDeserializer<E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("StringDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer holding a `Cow<str>`.
|
/// A deserializer holding a `Cow<str>`.
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
#[derive(Debug)]
|
#[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>,
|
||||||
@@ -601,6 +687,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,
|
||||||
@@ -608,8 +695,16 @@ where
|
|||||||
type Deserializer = CowStrDeserializer<'a, E>;
|
type Deserializer = CowStrDeserializer<'a, E>;
|
||||||
|
|
||||||
fn into_deserializer(self) -> CowStrDeserializer<'a, E> {
|
fn into_deserializer(self) -> CowStrDeserializer<'a, E> {
|
||||||
|
CowStrDeserializer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, E> CowStrDeserializer<'a, E> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub fn new(value: Cow<'a, str>) -> Self {
|
||||||
CowStrDeserializer {
|
CowStrDeserializer {
|
||||||
value: self,
|
value,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -669,29 +764,48 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
impl<'a, E> Debug for CowStrDeserializer<'a, E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("CowStrDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
/// A deserializer holding a `&[u8]`. Always calls [`Visitor::visit_bytes`].
|
||||||
/// deserializer.
|
pub struct BytesDeserializer<'a, E> {
|
||||||
#[derive(Debug)]
|
value: &'a [u8],
|
||||||
pub struct BorrowedBytesDeserializer<'de, E> {
|
|
||||||
value: &'de [u8],
|
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
|
impl<'a, E> BytesDeserializer<'a, E> {
|
||||||
|
/// Create a new deserializer from the given bytes.
|
||||||
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
pub fn new(value: &'a [u8]) -> Self {
|
||||||
/// Create a new borrowed deserializer from the given byte slice.
|
BytesDeserializer {
|
||||||
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
|
value,
|
||||||
BorrowedBytesDeserializer {
|
|
||||||
value: value,
|
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
|
impl_copy_clone!(BytesDeserializer<'a>);
|
||||||
|
|
||||||
|
impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a [u8]
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
type Deserializer = BytesDeserializer<'a, E>;
|
||||||
|
|
||||||
|
fn into_deserializer(self) -> BytesDeserializer<'a, E> {
|
||||||
|
BytesDeserializer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
|
||||||
where
|
where
|
||||||
E: de::Error,
|
E: de::Error,
|
||||||
{
|
{
|
||||||
@@ -699,7 +813,55 @@ where
|
|||||||
|
|
||||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E> Debug for BytesDeserializer<'a, E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("BytesDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
||||||
|
/// deserializer. Always calls [`Visitor::visit_borrowed_bytes`].
|
||||||
|
pub struct BorrowedBytesDeserializer<'de, E> {
|
||||||
|
value: &'de [u8],
|
||||||
|
marker: PhantomData<E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
||||||
|
/// Create a new borrowed deserializer from the given borrowed bytes.
|
||||||
|
pub fn new(value: &'de [u8]) -> Self {
|
||||||
|
BorrowedBytesDeserializer {
|
||||||
|
value,
|
||||||
|
marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
|
||||||
|
|
||||||
|
impl<'de, E> Deserializer<'de> for BorrowedBytesDeserializer<'de, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_borrowed_bytes(self.value)
|
visitor.visit_borrowed_bytes(self.value)
|
||||||
}
|
}
|
||||||
@@ -707,14 +869,23 @@ where
|
|||||||
forward_to_deserialize_any! {
|
forward_to_deserialize_any! {
|
||||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
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
|
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||||
tuple_struct map struct identifier ignored_any enum
|
tuple_struct map struct enum identifier ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, E> Debug for BorrowedBytesDeserializer<'de, E> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("BorrowedBytesDeserializer")
|
||||||
|
.field("value", &self.value)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// A deserializer that iterates over a sequence.
|
/// A deserializer that iterates over a sequence.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct SeqDeserializer<I, E> {
|
pub struct SeqDeserializer<I, E> {
|
||||||
iter: iter::Fuse<I>,
|
iter: iter::Fuse<I>,
|
||||||
count: usize,
|
count: usize,
|
||||||
@@ -769,8 +940,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,16 +983,30 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<I, E> Debug for SeqDeserializer<I, E>
|
||||||
|
where
|
||||||
|
I: Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("SeqDeserializer")
|
||||||
|
.field("iter", &self.iter)
|
||||||
|
.field("count", &self.count)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[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>,
|
||||||
@@ -835,6 +1020,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,
|
||||||
@@ -848,6 +1034,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,
|
||||||
@@ -872,7 +1059,7 @@ pub struct SeqAccessDeserializer<A> {
|
|||||||
impl<A> SeqAccessDeserializer<A> {
|
impl<A> SeqAccessDeserializer<A> {
|
||||||
/// Construct a new `SeqAccessDeserializer<A>`.
|
/// Construct a new `SeqAccessDeserializer<A>`.
|
||||||
pub fn new(seq: A) -> Self {
|
pub fn new(seq: A) -> Self {
|
||||||
SeqAccessDeserializer { seq: seq }
|
SeqAccessDeserializer { seq }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,8 +1168,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,8 +1177,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,7 +1227,7 @@ where
|
|||||||
let value = self.value.take();
|
let value = self.value.take();
|
||||||
// Panic because this indicates a bug in the program rather than an
|
// Panic because this indicates a bug in the program rather than an
|
||||||
// expected failure.
|
// expected failure.
|
||||||
let value = value.expect("MapAccess::visit_value called before visit_key");
|
let value = value.expect("MapAccess::next_value called before next_key");
|
||||||
seed.deserialize(value.into_deserializer())
|
seed.deserialize(value.into_deserializer())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1055,8 +1242,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),
|
||||||
@@ -1114,7 +1301,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot #[derive(Debug)] because of the bound `Second<I::Item>: Debug`.
|
|
||||||
impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
|
impl<'de, I, E> Debug for MapDeserializer<'de, I, E>
|
||||||
where
|
where
|
||||||
I: Iterator + Debug,
|
I: Iterator + Debug,
|
||||||
@@ -1127,8 +1313,6 @@ where
|
|||||||
.field("iter", &self.iter)
|
.field("iter", &self.iter)
|
||||||
.field("value", &self.value)
|
.field("value", &self.value)
|
||||||
.field("count", &self.count)
|
.field("count", &self.count)
|
||||||
.field("lifetime", &self.lifetime)
|
|
||||||
.field("error", &self.error)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1163,7 +1347,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 {
|
||||||
@@ -1227,7 +1411,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)
|
||||||
}
|
}
|
||||||
@@ -1237,6 +1421,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,
|
||||||
@@ -1251,6 +1436,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,
|
||||||
@@ -1276,7 +1462,7 @@ pub struct MapAccessDeserializer<A> {
|
|||||||
impl<A> MapAccessDeserializer<A> {
|
impl<A> MapAccessDeserializer<A> {
|
||||||
/// Construct a new `MapAccessDeserializer<A>`.
|
/// Construct a new `MapAccessDeserializer<A>`.
|
||||||
pub fn new(map: A) -> Self {
|
pub fn new(map: A) -> Self {
|
||||||
MapAccessDeserializer { map: map }
|
MapAccessDeserializer { map }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1293,6 +1479,71 @@ where
|
|||||||
visitor.visit_map(self.map)
|
visitor.visit_map(self.map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_enum<V>(
|
||||||
|
self,
|
||||||
|
_name: &str,
|
||||||
|
_variants: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_enum(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 identifier ignored_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
|
||||||
|
where
|
||||||
|
A: de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
type Error = A::Error;
|
||||||
|
type Variant = private::MapAsEnum<A>;
|
||||||
|
|
||||||
|
fn variant_seed<T>(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
|
||||||
|
where
|
||||||
|
T: de::DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
match tri!(self.map.next_key_seed(seed)) {
|
||||||
|
Some(key) => Ok((key, private::map_as_enum(self.map))),
|
||||||
|
None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// A deserializer holding an `EnumAccess`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct EnumAccessDeserializer<A> {
|
||||||
|
access: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> EnumAccessDeserializer<A> {
|
||||||
|
/// Construct a new `EnumAccessDeserializer<A>`.
|
||||||
|
pub fn new(access: A) -> Self {
|
||||||
|
EnumAccessDeserializer { access }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, A> de::Deserializer<'de> for EnumAccessDeserializer<A>
|
||||||
|
where
|
||||||
|
A: de::EnumAccess<'de>,
|
||||||
|
{
|
||||||
|
type Error = A::Error;
|
||||||
|
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_enum(self.access)
|
||||||
|
}
|
||||||
|
|
||||||
forward_to_deserialize_any! {
|
forward_to_deserialize_any! {
|
||||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
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
|
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||||
@@ -1303,11 +1554,12 @@ where
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
use lib::*;
|
use crate::lib::*;
|
||||||
|
|
||||||
use de::{self, Unexpected};
|
use crate::de::{
|
||||||
|
self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct UnitOnly<E> {
|
pub struct UnitOnly<E> {
|
||||||
marker: PhantomData<E>,
|
marker: PhantomData<E>,
|
||||||
}
|
}
|
||||||
@@ -1366,6 +1618,87 @@ mod private {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MapAsEnum<A> {
|
||||||
|
map: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
|
||||||
|
MapAsEnum { map }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
|
||||||
|
where
|
||||||
|
A: MapAccess<'de>,
|
||||||
|
{
|
||||||
|
type Error = A::Error;
|
||||||
|
|
||||||
|
fn unit_variant(mut self) -> Result<(), Self::Error> {
|
||||||
|
self.map.next_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
self.map.next_value_seed(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.map.next_value_seed(SeedTupleVariant { len, visitor })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_variant<V>(
|
||||||
|
mut self,
|
||||||
|
_fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.map.next_value_seed(SeedStructVariant { visitor })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SeedTupleVariant<V> {
|
||||||
|
len: usize,
|
||||||
|
visitor: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant<V>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
type Value = V::Value;
|
||||||
|
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_tuple(self.len, self.visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SeedStructVariant<V> {
|
||||||
|
visitor: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, V> DeserializeSeed<'de> for SeedStructVariant<V>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
type Value = V::Value;
|
||||||
|
|
||||||
|
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_map(self.visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Avoid having to restate the generic types on `MapDeserializer`. The
|
/// Avoid having to restate the generic types on `MapDeserializer`. The
|
||||||
/// `Iterator::Item` contains enough information to figure out K and V.
|
/// `Iterator::Item` contains enough information to figure out K and V.
|
||||||
pub trait Pair {
|
pub trait Pair {
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
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::result::Result::{self, Err, Ok};
|
|
||||||
|
|
||||||
pub use self::string::from_utf8_lossy;
|
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
|
||||||
pub use lib::Vec;
|
|
||||||
|
|
||||||
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::export::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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-80
@@ -1,86 +1,9 @@
|
|||||||
/// Conditional compilation depending on whether Serde is built with support for
|
// No longer used. Old versions of serde used this macro for supporting targets
|
||||||
/// 128-bit integers.
|
// that did not yet have 128-bit integer support.
|
||||||
///
|
|
||||||
/// Data formats that wish to support Rust compiler versions older than 1.26 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
|
|
||||||
/// do not need to bother with this macro and may assume support for 128-bit
|
|
||||||
/// integers.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// #[macro_use]
|
|
||||||
/// extern crate serde;
|
|
||||||
///
|
|
||||||
/// use serde::Serializer;
|
|
||||||
/// # use serde::private::ser::Error;
|
|
||||||
/// #
|
|
||||||
/// # struct MySerializer;
|
|
||||||
///
|
|
||||||
/// 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!()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// #
|
|
||||||
/// # __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
|
|
||||||
/// # }
|
|
||||||
/// }
|
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// When Serde is built with support for 128-bit integers, this macro expands
|
|
||||||
/// transparently into just the input tokens.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// macro_rules! serde_if_integer128 {
|
|
||||||
/// ($($tt:tt)*) => {
|
|
||||||
/// $($tt)*
|
|
||||||
/// };
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// When built without support for 128-bit integers, this macro expands to
|
|
||||||
/// nothing.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// macro_rules! serde_if_integer128 {
|
|
||||||
/// ($($tt:tt)*) => {};
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[cfg(integer128)]
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
macro_rules! serde_if_integer128 {
|
macro_rules! serde_if_integer128 {
|
||||||
($($tt:tt)*) => {
|
($($tt:tt)*) => {
|
||||||
$($tt)*
|
$($tt)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(integer128))]
|
|
||||||
#[macro_export]
|
|
||||||
#[doc(hidden)]
|
|
||||||
macro_rules! serde_if_integer128 {
|
|
||||||
($($tt:tt)*) => {};
|
|
||||||
}
|
|
||||||
|
|||||||
+172
-130
@@ -9,11 +9,9 @@
|
|||||||
//! 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.
|
||||||
//!
|
//!
|
||||||
//! [https://serde.rs/]: https://serde.rs/
|
|
||||||
//!
|
|
||||||
//! ## Design
|
//! ## Design
|
||||||
//!
|
//!
|
||||||
//! Where many other languages rely on runtime reflection for serializing data,
|
//! Where many other languages rely on runtime reflection for serializing data,
|
||||||
@@ -33,12 +31,11 @@
|
|||||||
//! for Serde by the community.
|
//! for Serde by the community.
|
||||||
//!
|
//!
|
||||||
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
|
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
|
||||||
//! - [Bincode], a compact binary format
|
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
|
||||||
//! used for IPC within the Servo rendering engine.
|
|
||||||
//! - [CBOR], a Concise Binary Object Representation designed for small message
|
//! - [CBOR], a Concise Binary Object Representation designed for small message
|
||||||
//! size without the need for version negotiation.
|
//! size without the need for version negotiation.
|
||||||
//! - [YAML], a popular human-friendly configuration language that ain't markup
|
//! - [YAML], a self-proclaimed human-friendly configuration language that ain't
|
||||||
//! language.
|
//! markup language.
|
||||||
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
|
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
|
||||||
//! - [TOML], a minimal configuration format used by [Cargo].
|
//! - [TOML], a minimal configuration format used by [Cargo].
|
||||||
//! - [Pickle], a format common in the Python world.
|
//! - [Pickle], a format common in the Python world.
|
||||||
@@ -46,92 +43,118 @@
|
|||||||
//! - [BSON], the data storage and network transfer format used by MongoDB.
|
//! - [BSON], the data storage and network transfer format used by MongoDB.
|
||||||
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
|
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
|
||||||
//! definition.
|
//! definition.
|
||||||
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
|
//! - [JSON5], a superset of JSON including some productions from ES5.
|
||||||
//! - [JSON5], A superset of JSON including some productions from ES5.
|
//! - [URL] query strings, in the x-www-form-urlencoded format.
|
||||||
//! - [URL], the x-www-form-urlencoded format.
|
//! - [Starlark], the format used for describing build targets by the Bazel and
|
||||||
|
//! Buck build systems. *(serialization only)*
|
||||||
//! - [Envy], a way to deserialize environment variables into Rust structs.
|
//! - [Envy], a way to deserialize environment variables into Rust structs.
|
||||||
//! *(deserialization only)*
|
//! *(deserialization only)*
|
||||||
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
|
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
|
||||||
//! Rust structs. *(deserialization only)*
|
//! Rust structs. *(deserialization only)*
|
||||||
|
//! - [S-expressions], the textual representation of code and data used by the
|
||||||
|
//! Lisp language family.
|
||||||
|
//! - [D-Bus]'s binary wire format.
|
||||||
|
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy
|
||||||
|
//! serialization format.
|
||||||
|
//! - [Bencode], a simple binary format used in the BitTorrent protocol.
|
||||||
|
//! - [Token streams], for processing Rust procedural macro input.
|
||||||
|
//! *(deserialization only)*
|
||||||
|
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
|
||||||
|
//! and from DynamoDB.
|
||||||
|
//! - [Hjson], a syntax extension to JSON designed around human reading and
|
||||||
|
//! editing. *(deserialization only)*
|
||||||
|
//! - [CSV], Comma-separated values is a tabular text file format.
|
||||||
//!
|
//!
|
||||||
//! [JSON]: https://github.com/serde-rs/json
|
//! [JSON]: https://github.com/serde-rs/json
|
||||||
//! [Bincode]: https://github.com/TyOverby/bincode
|
//! [Postcard]: https://github.com/jamesmunns/postcard
|
||||||
//! [CBOR]: https://github.com/pyfisch/cbor
|
//! [CBOR]: https://github.com/enarx/ciborium
|
||||||
//! [YAML]: https://github.com/dtolnay/serde-yaml
|
//! [YAML]: https://github.com/dtolnay/serde-yaml
|
||||||
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
|
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
|
||||||
//! [TOML]: https://github.com/alexcrichton/toml-rs
|
//! [TOML]: https://docs.rs/toml
|
||||||
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
|
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
|
||||||
//! [RON]: https://github.com/ron-rs/ron
|
//! [RON]: https://github.com/ron-rs/ron
|
||||||
//! [BSON]: https://github.com/zonyitoo/bson-rs
|
//! [BSON]: https://github.com/mongodb/bson-rust
|
||||||
//! [Avro]: https://github.com/flavray/avro-rs
|
//! [Avro]: https://docs.rs/apache-avro
|
||||||
//! [Hjson]: https://github.com/laktak/hjson-rust
|
|
||||||
//! [JSON5]: https://github.com/callum-oakley/json5-rs
|
//! [JSON5]: https://github.com/callum-oakley/json5-rs
|
||||||
//! [URL]: https://github.com/nox/serde_urlencoded
|
//! [URL]: https://docs.rs/serde_qs
|
||||||
|
//! [Starlark]: https://github.com/dtolnay/serde-starlark
|
||||||
//! [Envy]: https://github.com/softprops/envy
|
//! [Envy]: https://github.com/softprops/envy
|
||||||
//! [Envy Store]: https://github.com/softprops/envy-store
|
//! [Envy Store]: https://github.com/softprops/envy-store
|
||||||
//! [Cargo]: http://doc.crates.io/manifest.html
|
//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
|
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html
|
||||||
|
//! [S-expressions]: https://github.com/rotty/lexpr-rs
|
||||||
|
//! [D-Bus]: https://docs.rs/zvariant
|
||||||
|
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
|
||||||
|
//! [Bencode]: https://github.com/P3KI/bendy
|
||||||
|
//! [Token streams]: https://github.com/oxidecomputer/serde_tokenstream
|
||||||
|
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
|
||||||
|
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb
|
||||||
|
//! [Hjson]: https://github.com/Canop/deser-hjson
|
||||||
|
//! [CSV]: https://docs.rs/csv
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Serde types in rustdoc of other crates get linked to here.
|
// Serde types in rustdoc of other crates get linked to here.
|
||||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.81")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.209")]
|
||||||
// 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(specialization, never_type))]
|
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
// Ignored clippy and clippy_pedantic lints
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
#![allow(
|
||||||
// Whitelisted clippy lints
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||||
#![cfg_attr(
|
clippy::unnested_or_patterns,
|
||||||
feature = "cargo-clippy",
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
|
||||||
allow(
|
clippy::semicolon_if_nothing_returned,
|
||||||
cast_lossless,
|
// not available in our oldest supported compiler
|
||||||
const_static_lifetime,
|
clippy::empty_enum,
|
||||||
doc_markdown,
|
clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
||||||
linkedlist,
|
// integer and float ser/de requires these sorts of casts
|
||||||
needless_pass_by_value,
|
clippy::cast_possible_truncation,
|
||||||
redundant_field_names,
|
clippy::cast_possible_wrap,
|
||||||
type_complexity,
|
clippy::cast_precision_loss,
|
||||||
unreadable_literal,
|
clippy::cast_sign_loss,
|
||||||
zero_prefixed_literal
|
// 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::unseparated_literal_suffix,
|
||||||
|
// false positive
|
||||||
|
clippy::needless_doctest_main,
|
||||||
|
// noisy
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::must_use_candidate,
|
||||||
)]
|
)]
|
||||||
// Whitelisted clippy_pedantic lints
|
// Restrictions
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
#![deny(clippy::question_mark_used)]
|
||||||
// integer and float ser/de requires these sorts of casts
|
// Rustc lints.
|
||||||
cast_possible_truncation,
|
#![deny(missing_docs, unused_imports)]
|
||||||
cast_possible_wrap,
|
|
||||||
cast_precision_loss,
|
|
||||||
cast_sign_loss,
|
|
||||||
// simplifies some macros
|
|
||||||
invalid_upcast_comparisons,
|
|
||||||
// things are often more readable this way
|
|
||||||
decimal_literal_representation,
|
|
||||||
option_unwrap_used,
|
|
||||||
result_unwrap_used,
|
|
||||||
shadow_reuse,
|
|
||||||
single_match_else,
|
|
||||||
stutter,
|
|
||||||
use_self,
|
|
||||||
// not practical
|
|
||||||
indexing_slicing,
|
|
||||||
many_single_char_names,
|
|
||||||
missing_docs_in_private_items,
|
|
||||||
similar_names,
|
|
||||||
// alternative is not stable
|
|
||||||
empty_enum,
|
|
||||||
use_debug,
|
|
||||||
))]
|
|
||||||
// Blacklisted Rust lints.
|
|
||||||
//
|
|
||||||
// Compiler bug involving unused_imports:
|
|
||||||
// https://github.com/rust-lang/rust/issues/51661
|
|
||||||
#![deny(missing_docs, /*unused_imports*/)]
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -149,20 +172,26 @@ mod lib {
|
|||||||
pub use std::*;
|
pub use std::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::core::{cmp, iter, mem, num, slice, str};
|
|
||||||
pub use self::core::{f32, f64};
|
pub use self::core::{f32, f64};
|
||||||
pub use self::core::{i16, i32, i64, i8, isize};
|
pub use self::core::{i16, i32, i64, i8, isize};
|
||||||
|
pub use self::core::{iter, num, ptr, str};
|
||||||
pub use self::core::{u16, u32, u64, u8, usize};
|
pub use self::core::{u16, u32, u64, u8, usize};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub use self::core::{cmp, mem, slice};
|
||||||
|
|
||||||
pub use self::core::cell::{Cell, RefCell};
|
pub use self::core::cell::{Cell, RefCell};
|
||||||
pub use self::core::clone::{self, Clone};
|
pub use self::core::clone;
|
||||||
pub use self::core::convert::{self, From, Into};
|
pub use self::core::cmp::Reverse;
|
||||||
pub use self::core::default::{self, Default};
|
pub use self::core::convert;
|
||||||
pub use self::core::fmt::{self, Debug, Display};
|
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::marker::{self, PhantomData};
|
||||||
pub use self::core::ops::Range;
|
pub use self::core::num::Wrapping;
|
||||||
pub use self::core::option::{self, Option};
|
pub use self::core::ops::{Bound, Range, RangeFrom, RangeInclusive, RangeTo};
|
||||||
pub use self::core::result::{self, Result};
|
pub use self::core::option;
|
||||||
|
pub use self::core::result;
|
||||||
|
pub use self::core::time::Duration;
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
pub use alloc::borrow::{Cow, ToOwned};
|
pub use alloc::borrow::{Cow, ToOwned};
|
||||||
@@ -172,7 +201,7 @@ mod lib {
|
|||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
pub use alloc::string::{String, ToString};
|
pub use alloc::string::{String, ToString};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::string::String;
|
pub use std::string::{String, ToString};
|
||||||
|
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
pub use alloc::vec::Vec;
|
pub use alloc::vec::Vec;
|
||||||
@@ -199,31 +228,70 @@ mod lib {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||||
|
|
||||||
|
#[cfg(all(not(no_core_cstr), not(feature = "std")))]
|
||||||
|
pub use self::core::ffi::CStr;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use std::ffi::CStr;
|
||||||
|
|
||||||
|
#[cfg(all(not(no_core_cstr), feature = "alloc", not(feature = "std")))]
|
||||||
|
pub use alloc::ffi::CString;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use std::ffi::CString;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::{error, net};
|
pub use std::{error, net};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::collections::{HashMap, HashSet};
|
pub use std::collections::{HashMap, HashSet};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::ffi::{CStr, CString, OsStr, OsString};
|
pub use std::ffi::{OsStr, OsString};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::hash::{BuildHasher, Hash};
|
pub use std::hash::{BuildHasher, Hash};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::io::Write;
|
pub use std::io::Write;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::num::Wrapping;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub use std::path::{Path, PathBuf};
|
pub use std::path::{Path, PathBuf};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::sync::{Mutex, RwLock};
|
pub use std::sync::{Mutex, RwLock};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use std::time::{SystemTime, UNIX_EPOCH};
|
pub use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
#[cfg(any(core_duration, feature = "std"))]
|
#[cfg(all(feature = "std", no_target_has_atomic, not(no_std_atomic)))]
|
||||||
pub use self::core::time::Duration;
|
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(range_inclusive)]
|
#[cfg(all(feature = "std", not(no_target_has_atomic)))]
|
||||||
pub use self::core::ops::RangeInclusive;
|
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),
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -238,61 +306,35 @@ pub mod de;
|
|||||||
pub mod ser;
|
pub mod ser;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use de::{Deserialize, Deserializer};
|
pub use crate::de::{Deserialize, Deserializer};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use ser::{Serialize, Serializer};
|
pub use crate::ser::{Serialize, Serializer};
|
||||||
|
|
||||||
// Generated code uses these to support no_std. Not public API.
|
// Used by generated code and doc tests. Not public API.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod export;
|
#[path = "private/mod.rs"]
|
||||||
|
pub mod __private;
|
||||||
|
|
||||||
// Helpers used by generated code and doc tests. Not public API.
|
#[path = "de/seed.rs"]
|
||||||
#[doc(hidden)]
|
mod seed;
|
||||||
pub mod private;
|
|
||||||
|
#[cfg(not(any(feature = "std", feature = "unstable")))]
|
||||||
|
mod std_error;
|
||||||
|
|
||||||
// Re-export #[derive(Serialize, Deserialize)].
|
// Re-export #[derive(Serialize, Deserialize)].
|
||||||
//
|
//
|
||||||
// This is a workaround for https://github.com/rust-lang/cargo/issues/1286.
|
|
||||||
// Without this re-export, crates that put Serde derives behind a cfg_attr would
|
|
||||||
// need to use some silly feature name that depends on both serde and
|
|
||||||
// serde_derive.
|
|
||||||
//
|
|
||||||
// [features]
|
|
||||||
// serde-impls = ["serde", "serde_derive"]
|
|
||||||
//
|
|
||||||
// [dependencies]
|
|
||||||
// serde = { version = "1.0", optional = true }
|
|
||||||
// serde_derive = { version = "1.0", optional = true }
|
|
||||||
//
|
|
||||||
// # Used like this:
|
|
||||||
// # #[cfg(feature = "serde-impls")]
|
|
||||||
// # #[macro_use]
|
|
||||||
// # extern crate serde_derive;
|
|
||||||
// #
|
|
||||||
// # #[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
|
|
||||||
// # struct S { /* ... */ }
|
|
||||||
//
|
|
||||||
// The re-exported derives allow crates to use "serde" as the name of their
|
|
||||||
// Serde feature which is more intuitive.
|
|
||||||
//
|
|
||||||
// [dependencies]
|
|
||||||
// serde = { version = "1.0", optional = true, features = ["derive"] }
|
|
||||||
//
|
|
||||||
// # Used like this:
|
|
||||||
// # #[cfg(feature = "serde")]
|
|
||||||
// # #[macro_use]
|
|
||||||
// # extern crate serde;
|
|
||||||
// #
|
|
||||||
// # #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
||||||
// # struct S { /* ... */ }
|
|
||||||
//
|
|
||||||
// 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"]`.
|
||||||
#[cfg(feature = "serde_derive")]
|
#[cfg(feature = "serde_derive")]
|
||||||
#[doc(hidden)]
|
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
|
||||||
pub use serde_derive::*;
|
pub use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
|
||||||
|
mod actually_private {
|
||||||
|
pub struct T;
|
||||||
|
}
|
||||||
|
|||||||
+10
-27
@@ -11,10 +11,8 @@
|
|||||||
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
||||||
/// trait methods.
|
/// trait methods.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # #[macro_use]
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # extern crate serde;
|
|
||||||
/// #
|
|
||||||
/// # use serde::de::{value, Deserializer, Visitor};
|
/// # use serde::de::{value, Deserializer, Visitor};
|
||||||
/// #
|
/// #
|
||||||
/// # struct MyDeserializer;
|
/// # struct MyDeserializer;
|
||||||
@@ -43,18 +41,14 @@
|
|||||||
/// # tuple_struct map struct enum identifier ignored_any
|
/// # tuple_struct map struct enum identifier ignored_any
|
||||||
/// # }
|
/// # }
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The `forward_to_deserialize_any!` macro implements these simple forwarding
|
/// The `forward_to_deserialize_any!` macro implements these simple forwarding
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # #[macro_use]
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # extern crate serde;
|
|
||||||
/// #
|
|
||||||
/// # use serde::de::{value, Deserializer, Visitor};
|
/// # use serde::de::{value, Deserializer, Visitor};
|
||||||
/// #
|
/// #
|
||||||
/// # struct MyDeserializer;
|
/// # struct MyDeserializer;
|
||||||
@@ -77,8 +71,6 @@
|
|||||||
/// tuple_struct map struct enum identifier ignored_any
|
/// tuple_struct map struct enum identifier ignored_any
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The macro assumes the convention that your `Deserializer` lifetime parameter
|
/// The macro assumes the convention that your `Deserializer` lifetime parameter
|
||||||
@@ -86,13 +78,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.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # #[macro_use]
|
/// # use serde::forward_to_deserialize_any;
|
||||||
/// # extern crate serde;
|
|
||||||
/// #
|
|
||||||
/// # use std::marker::PhantomData;
|
|
||||||
/// #
|
|
||||||
/// # 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>);
|
||||||
/// #
|
/// #
|
||||||
@@ -113,8 +102,6 @@
|
|||||||
/// tuple_struct map struct enum identifier ignored_any
|
/// tuple_struct map struct enum identifier ignored_any
|
||||||
/// }
|
/// }
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Deserializer`]: trait.Deserializer.html
|
/// [`Deserializer`]: trait.Deserializer.html
|
||||||
@@ -136,7 +123,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::export::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>,
|
||||||
{
|
{
|
||||||
@@ -167,9 +154,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>()}
|
||||||
@@ -184,9 +169,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>()}
|
||||||
|
|||||||
+457
-597
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,35 @@
|
|||||||
|
// Used only by Serde doc tests. Not public API.
|
||||||
|
|
||||||
|
use crate::lib::*;
|
||||||
|
|
||||||
|
use crate::ser;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error;
|
||||||
|
|
||||||
|
impl ser::Error for Error {
|
||||||
|
fn custom<T>(_: T) -> Self
|
||||||
|
where
|
||||||
|
T: Display,
|
||||||
|
{
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! __private_serialize {
|
macro_rules! __private_serialize {
|
||||||
@@ -10,19 +42,6 @@ macro_rules! __private_serialize {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! __private_deserialize {
|
|
||||||
() => {
|
|
||||||
trait Deserialize<'de>: Sized {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: $crate::Deserializer<'de>;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used only by Serde doc tests. Not public API.
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export(local_inner_macros)]
|
#[macro_export(local_inner_macros)]
|
||||||
macro_rules! __serialize_unimplemented {
|
macro_rules! __serialize_unimplemented {
|
||||||
@@ -37,7 +56,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::export::Result<Self::$ret, Self::Error> {
|
fn $func $(<$t>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error>
|
||||||
|
where
|
||||||
|
$($t: ?Sized + $crate::Serialize,)*
|
||||||
|
{
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,4 +1,48 @@
|
|||||||
mod macros;
|
#[cfg(not(no_serde_derive))]
|
||||||
|
|
||||||
pub mod de;
|
pub mod de;
|
||||||
|
#[cfg(not(no_serde_derive))]
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
|
|
||||||
|
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||||
|
pub mod doc;
|
||||||
|
|
||||||
|
pub use crate::lib::clone::Clone;
|
||||||
|
pub use crate::lib::convert::{From, Into};
|
||||||
|
pub use crate::lib::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};
|
||||||
|
|
||||||
|
pub use self::string::from_utf8_lossy;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
|
pub use crate::lib::{ToString, Vec};
|
||||||
|
|
||||||
|
#[cfg(not(no_core_try_from))]
|
||||||
|
pub use crate::lib::convert::TryFrom;
|
||||||
|
|
||||||
|
mod string {
|
||||||
|
use crate::lib::*;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||||
|
String::from_utf8_lossy(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The generated code calls this like:
|
||||||
|
//
|
||||||
|
// let value = &_serde::__private::from_utf8_lossy(bytes);
|
||||||
|
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
|
||||||
|
//
|
||||||
|
// so it is okay for the return type to be different from the std case as long
|
||||||
|
// as the above works.
|
||||||
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||||
|
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||||
|
// Three unicode replacement characters if it fails. They look like a
|
||||||
|
// white-on-black question mark. The user will recognize it as invalid
|
||||||
|
// UTF-8.
|
||||||
|
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+241
-207
@@ -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::{
|
||||||
@@ -27,10 +27,10 @@ where
|
|||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
value.serialize(TaggedSerializer {
|
value.serialize(TaggedSerializer {
|
||||||
type_ident: type_ident,
|
type_ident,
|
||||||
variant_ident: variant_ident,
|
variant_ident,
|
||||||
tag: tag,
|
tag,
|
||||||
variant_name: variant_name,
|
variant_name,
|
||||||
delegate: serializer,
|
delegate: serializer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -51,9 +51,6 @@ enum Unsupported {
|
|||||||
String,
|
String,
|
||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
Unit,
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
UnitStruct,
|
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
@@ -70,9 +67,6 @@ 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"),
|
||||||
Unsupported::Unit => formatter.write_str("unit"),
|
|
||||||
#[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"),
|
||||||
@@ -176,20 +170,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> {
|
||||||
Err(self.bad_type(Unsupported::Unit))
|
let mut map = tri!(self.delegate.serialize_map(Some(1)));
|
||||||
|
tri!(map.serialize_entry(self.tag, self.variant_name));
|
||||||
|
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 +195,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 +220,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 +265,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 +276,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 +286,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 +312,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,46 +323,19 @@ 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used only by Serde doc tests. Not public API.
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Error;
|
|
||||||
|
|
||||||
impl ser::Error for Error {
|
|
||||||
fn custom<T>(_: T) -> Self
|
|
||||||
where
|
|
||||||
T: Display,
|
|
||||||
{
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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,
|
||||||
@@ -377,8 +346,8 @@ mod content {
|
|||||||
impl<M> SerializeTupleVariantAsMapValue<M> {
|
impl<M> SerializeTupleVariantAsMapValue<M> {
|
||||||
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
||||||
SerializeTupleVariantAsMapValue {
|
SerializeTupleVariantAsMapValue {
|
||||||
map: map,
|
map,
|
||||||
name: name,
|
name,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,17 +360,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()
|
||||||
@@ -417,8 +386,8 @@ mod content {
|
|||||||
impl<M> SerializeStructVariantAsMapValue<M> {
|
impl<M> SerializeStructVariantAsMapValue<M> {
|
||||||
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
||||||
SerializeStructVariantAsMapValue {
|
SerializeStructVariantAsMapValue {
|
||||||
map: map,
|
map,
|
||||||
name: name,
|
name,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,28 +400,23 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Content {
|
pub enum Content {
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
|
||||||
@@ -527,50 +491,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 &(ref k, ref 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()
|
||||||
}
|
}
|
||||||
@@ -663,11 +627,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> {
|
||||||
@@ -687,21 +651,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,
|
||||||
@@ -709,13 +669,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))),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,7 +699,7 @@ mod content {
|
|||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleStruct, E> {
|
) -> Result<Self::SerializeTupleStruct, E> {
|
||||||
Ok(SerializeTupleStruct {
|
Ok(SerializeTupleStruct {
|
||||||
name: name,
|
name,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
error: PhantomData,
|
error: PhantomData,
|
||||||
})
|
})
|
||||||
@@ -753,9 +713,9 @@ mod content {
|
|||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, E> {
|
) -> Result<Self::SerializeTupleVariant, E> {
|
||||||
Ok(SerializeTupleVariant {
|
Ok(SerializeTupleVariant {
|
||||||
name: name,
|
name,
|
||||||
variant_index: variant_index,
|
variant_index,
|
||||||
variant: variant,
|
variant,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
error: PhantomData,
|
error: PhantomData,
|
||||||
})
|
})
|
||||||
@@ -775,7 +735,7 @@ mod content {
|
|||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStruct, E> {
|
) -> Result<Self::SerializeStruct, E> {
|
||||||
Ok(SerializeStruct {
|
Ok(SerializeStruct {
|
||||||
name: name,
|
name,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
error: PhantomData,
|
error: PhantomData,
|
||||||
})
|
})
|
||||||
@@ -789,9 +749,9 @@ mod content {
|
|||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, E> {
|
) -> Result<Self::SerializeStructVariant, E> {
|
||||||
Ok(SerializeStructVariant {
|
Ok(SerializeStructVariant {
|
||||||
name: name,
|
name,
|
||||||
variant_index: variant_index,
|
variant_index,
|
||||||
variant: variant,
|
variant,
|
||||||
fields: Vec::with_capacity(len),
|
fields: Vec::with_capacity(len),
|
||||||
error: PhantomData,
|
error: PhantomData,
|
||||||
})
|
})
|
||||||
@@ -810,11 +770,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(())
|
||||||
}
|
}
|
||||||
@@ -836,11 +796,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(())
|
||||||
}
|
}
|
||||||
@@ -863,11 +823,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(())
|
||||||
}
|
}
|
||||||
@@ -892,11 +852,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(())
|
||||||
}
|
}
|
||||||
@@ -924,24 +884,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(())
|
||||||
}
|
}
|
||||||
@@ -950,13 +910,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(())
|
||||||
}
|
}
|
||||||
@@ -975,11 +935,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(())
|
||||||
}
|
}
|
||||||
@@ -1004,11 +964,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(())
|
||||||
}
|
}
|
||||||
@@ -1032,7 +992,7 @@ impl<'a, M> FlatMapSerializer<'a, M>
|
|||||||
where
|
where
|
||||||
M: SerializeMap + 'a,
|
M: SerializeMap + 'a,
|
||||||
{
|
{
|
||||||
fn bad_type(self, what: Unsupported) -> M::Error {
|
fn bad_type(what: Unsupported) -> M::Error {
|
||||||
ser::Error::custom(format_args!(
|
ser::Error::custom(format_args!(
|
||||||
"can only flatten structs and maps (got {})",
|
"can only flatten structs and maps (got {})",
|
||||||
what
|
what
|
||||||
@@ -1053,82 +1013,82 @@ 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> {
|
||||||
Err(self.bad_type(Unsupported::Boolean))
|
Err(Self::bad_type(Unsupported::Boolean))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Integer))
|
Err(Self::bad_type(Unsupported::Integer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Float))
|
Err(Self::bad_type(Unsupported::Float))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Float))
|
Err(Self::bad_type(Unsupported::Float))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Char))
|
Err(Self::bad_type(Unsupported::Char))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::String))
|
Err(Self::bad_type(Unsupported::String))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::ByteArray))
|
Err(Self::bad_type(Unsupported::ByteArray))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Unit))
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
@@ -1137,21 +1097,21 @@ where
|
|||||||
_: u32,
|
_: u32,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
) -> Result<Self::Ok, Self::Error> {
|
) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Enum))
|
Err(Self::bad_type(Unsupported::Enum))
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@@ -1159,18 +1119,17 @@ 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> {
|
||||||
Err(self.bad_type(Unsupported::Sequence))
|
Err(Self::bad_type(Unsupported::Sequence))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Tuple))
|
Err(Self::bad_type(Unsupported::Tuple))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple_struct(
|
fn serialize_tuple_struct(
|
||||||
@@ -1178,17 +1137,18 @@ where
|
|||||||
_: &'static str,
|
_: &'static str,
|
||||||
_: usize,
|
_: usize,
|
||||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::TupleStruct))
|
Err(Self::bad_type(Unsupported::TupleStruct))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple_variant(
|
fn serialize_tuple_variant(
|
||||||
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> {
|
||||||
@@ -1210,7 +1170,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,
|
||||||
@@ -1229,20 +1189,28 @@ 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, V>(&mut self, key: &K, value: &V) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
K: ?Sized + Serialize,
|
||||||
|
V: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
self.0.serialize_entry(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<(), Self::Error> {
|
fn end(self) -> Result<(), Self::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1259,13 +1227,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)
|
||||||
}
|
}
|
||||||
@@ -1275,6 +1239,52 @@ 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"))]
|
||||||
|
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,
|
||||||
@@ -1289,8 +1299,8 @@ where
|
|||||||
{
|
{
|
||||||
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
|
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
|
||||||
FlatMapSerializeStructVariantAsMapValue {
|
FlatMapSerializeStructVariantAsMapValue {
|
||||||
map: map,
|
map,
|
||||||
name: name,
|
name,
|
||||||
fields: Vec::new(),
|
fields: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1304,23 +1314,47 @@ 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
use crate::lib::*;
|
||||||
|
use crate::ser::{Error, Impossible, Serialize, Serializer};
|
||||||
|
|
||||||
|
impl Error for fmt::Error {
|
||||||
|
fn custom<T: Display>(_msg: T) -> Self {
|
||||||
|
fmt::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fmt_primitives {
|
||||||
|
($($f:ident: $t:ty,)*) => {
|
||||||
|
$(
|
||||||
|
fn $f(self, v: $t) -> fmt::Result {
|
||||||
|
Display::fmt(&v, self)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ```edition2021
|
||||||
|
/// use serde::ser::Serialize;
|
||||||
|
/// use serde_derive::Serialize;
|
||||||
|
/// use std::fmt::{self, Display};
|
||||||
|
///
|
||||||
|
/// #[derive(Serialize)]
|
||||||
|
/// #[serde(rename_all = "kebab-case")]
|
||||||
|
/// pub enum MessageType {
|
||||||
|
/// StartRequest,
|
||||||
|
/// EndRequest,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Display for MessageType {
|
||||||
|
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
/// self.serialize(f)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||||
|
type Ok = ();
|
||||||
|
type Error = fmt::Error;
|
||||||
|
type SerializeSeq = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeTuple = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeTupleStruct = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeTupleVariant = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeMap = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeStruct = Impossible<(), fmt::Error>;
|
||||||
|
type SerializeStructVariant = Impossible<(), fmt::Error>;
|
||||||
|
|
||||||
|
fmt_primitives! {
|
||||||
|
serialize_bool: bool,
|
||||||
|
serialize_i8: i8,
|
||||||
|
serialize_i16: i16,
|
||||||
|
serialize_i32: i32,
|
||||||
|
serialize_i64: i64,
|
||||||
|
serialize_i128: i128,
|
||||||
|
serialize_u8: u8,
|
||||||
|
serialize_u16: u16,
|
||||||
|
serialize_u32: u32,
|
||||||
|
serialize_u64: u64,
|
||||||
|
serialize_u128: u128,
|
||||||
|
serialize_f32: f32,
|
||||||
|
serialize_f64: f64,
|
||||||
|
serialize_char: char,
|
||||||
|
serialize_str: &str,
|
||||||
|
serialize_unit_struct: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
|
) -> fmt::Result {
|
||||||
|
Display::fmt(variant, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> fmt::Result
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
Serialize::serialize(value, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_bytes(self, _v: &[u8]) -> fmt::Result {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_none(self) -> fmt::Result {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_some<T>(self, _value: &T) -> fmt::Result
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_unit(self) -> fmt::Result {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_newtype_variant<T>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_value: &T,
|
||||||
|
) -> fmt::Result
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleStruct, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tuple_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeTupleVariant, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStruct, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_variant(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
_variant: &'static str,
|
||||||
|
_len: usize,
|
||||||
|
) -> Result<Self::SerializeStructVariant, fmt::Error> {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_str<T>(self, value: &T) -> fmt::Result
|
||||||
|
where
|
||||||
|
T: ?Sized + Display,
|
||||||
|
{
|
||||||
|
Display::fmt(value, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
+412
-101
@@ -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>
|
||||||
@@ -72,7 +70,8 @@ impl<'a> Serialize for fmt::Arguments<'a> {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[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>
|
||||||
@@ -83,7 +82,8 @@ impl Serialize for CStr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[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()
|
||||||
}
|
}
|
||||||
@@ -160,10 +163,12 @@ macro_rules! array_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
array_impls!(01 02 03 04 05 06 07 08 09 10
|
array_impls! {
|
||||||
11 12 13 14 15 16 17 18 19 20
|
01 02 03 04 05 06 07 08 09 10
|
||||||
21 22 23 24 25 26 27 28 29 30
|
11 12 13 14 15 16 17 18 19 20
|
||||||
31 32);
|
21 22 23 24 25 26 27 28 29 30
|
||||||
|
31 32
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -180,9 +185,35 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(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 $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)*>
|
||||||
|
) => {
|
||||||
|
$(#[$attr])*
|
||||||
|
impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.collect_seq(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(no_relaxed_trait_bounds)]
|
||||||
|
macro_rules! seq_impl {
|
||||||
|
(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
$ty:ident <T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $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 $(+ $tbound1 $(+ $tbound2)*)*,
|
T: Serialize $(+ $tbound1 $(+ $tbound2)*)*,
|
||||||
@@ -199,23 +230,41 @@ macro_rules! seq_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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"))))]
|
||||||
|
BinaryHeap<T: Ord>
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
seq_impl! {
|
||||||
seq_impl!(BTreeSet<T: Ord>);
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
|
BTreeSet<T: Ord>
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
seq_impl! {
|
||||||
seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>);
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
HashSet<T: Eq + Hash, H: BuildHasher>
|
||||||
|
}
|
||||||
|
|
||||||
#[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"))))]
|
||||||
|
LinkedList<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"))))]
|
||||||
|
Vec<T>
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
seq_impl! {
|
||||||
seq_impl!(VecDeque<T>);
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
|
VecDeque<T>
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -228,16 +277,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(range_inclusive)]
|
|
||||||
impl<Idx> Serialize for RangeInclusive<Idx>
|
impl<Idx> Serialize for RangeInclusive<Idx>
|
||||||
where
|
where
|
||||||
Idx: Serialize,
|
Idx: Serialize,
|
||||||
@@ -247,15 +312,54 @@ 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()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
impl<T> Serialize for Bound<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"),
|
||||||
|
Bound::Included(ref value) => {
|
||||||
|
serializer.serialize_newtype_variant("Bound", 1, "Included", value)
|
||||||
|
}
|
||||||
|
Bound::Excluded(ref value) => {
|
||||||
|
serializer.serialize_newtype_variant("Bound", 2, "Excluded", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl Serialize for () {
|
impl Serialize for () {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@@ -267,6 +371,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
|
||||||
@@ -281,28 +386,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)
|
||||||
@@ -322,9 +445,36 @@ tuple_impls! {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(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)*>
|
||||||
|
where
|
||||||
|
K: Serialize,
|
||||||
|
V: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.collect_map(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(no_relaxed_trait_bounds)]
|
||||||
|
macro_rules! map_impl {
|
||||||
|
(
|
||||||
|
$(#[$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 $(+ $kbound1 $(+ $kbound2)*)*,
|
K: Serialize $(+ $kbound1 $(+ $kbound2)*)*,
|
||||||
@@ -342,20 +492,26 @@ macro_rules! map_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
map_impl! {
|
||||||
map_impl!(BTreeMap<K: Ord, V>);
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
|
||||||
|
BTreeMap<K: Ord, V>
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
map_impl! {
|
||||||
map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
|
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>
|
||||||
@@ -368,13 +524,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.
|
||||||
///
|
///
|
||||||
@@ -384,10 +547,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.
|
||||||
///
|
///
|
||||||
@@ -397,11 +561,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
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -409,9 +578,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
|
||||||
@@ -425,9 +598,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
|
||||||
@@ -440,9 +617,8 @@ where
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
macro_rules! nonzero_integers {
|
macro_rules! nonzero_integers {
|
||||||
( $( $T: ident, )+ ) => {
|
($($T:ident,)+) => {
|
||||||
$(
|
$(
|
||||||
#[cfg(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
|
||||||
@@ -456,20 +632,22 @@ macro_rules! nonzero_integers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nonzero_integers! {
|
nonzero_integers! {
|
||||||
// Not including signed NonZeroI* since they might be removed
|
|
||||||
NonZeroU8,
|
NonZeroU8,
|
||||||
NonZeroU16,
|
NonZeroU16,
|
||||||
NonZeroU32,
|
NonZeroU32,
|
||||||
NonZeroU64,
|
NonZeroU64,
|
||||||
|
NonZeroU128,
|
||||||
NonZeroUsize,
|
NonZeroUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently 128-bit integers do not work on Emscripten targets so we need an
|
#[cfg(not(no_num_nonzero_signed))]
|
||||||
// additional `#[cfg]`
|
nonzero_integers! {
|
||||||
serde_if_integer128! {
|
NonZeroI8,
|
||||||
nonzero_integers! {
|
NonZeroI16,
|
||||||
NonZeroU128,
|
NonZeroI32,
|
||||||
}
|
NonZeroI64,
|
||||||
|
NonZeroI128,
|
||||||
|
NonZeroIsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Serialize for Cell<T>
|
impl<T> Serialize for Cell<T>
|
||||||
@@ -486,7 +664,7 @@ where
|
|||||||
|
|
||||||
impl<T> 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
|
||||||
@@ -500,9 +678,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl<T> Serialize for Mutex<T>
|
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
|
||||||
@@ -516,9 +695,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
impl<T> Serialize for RwLock<T>
|
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
|
||||||
@@ -553,16 +733,15 @@ where
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(any(core_duration, feature = "std"))]
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -570,18 +749,20 @@ 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
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
use super::SerializeStruct;
|
use super::SerializeStruct;
|
||||||
let duration_since_epoch = self
|
let duration_since_epoch = match self.duration_since(UNIX_EPOCH) {
|
||||||
.duration_since(UNIX_EPOCH)
|
Ok(duration_since_epoch) => duration_since_epoch,
|
||||||
.expect("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));
|
};
|
||||||
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
let mut state = tri!(serializer.serialize_struct("SystemTime", 2));
|
||||||
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
tri!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
||||||
|
tri!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
||||||
state.end()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,7 +776,7 @@ impl Serialize for SystemTime {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
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: [u8; $max] = unsafe { mem::uninitialized() };
|
let mut buffer = [0u8; $max];
|
||||||
let remaining_len = {
|
let remaining_len = {
|
||||||
let mut remaining = &mut buffer[..];
|
let mut remaining = &mut buffer[..];
|
||||||
write!(remaining, "{}", $value).unwrap();
|
write!(remaining, "{}", $value).unwrap();
|
||||||
@@ -607,12 +788,13 @@ macro_rules! serialize_display_bounded_length {
|
|||||||
// write! only provides fmt::Formatter to Display implementations, which
|
// write! only provides fmt::Formatter to Display implementations, which
|
||||||
// has methods write_str and write_char but no method to write arbitrary
|
// has methods write_str and write_char but no method to write arbitrary
|
||||||
// bytes. Therefore `written` must be valid UTF-8.
|
// bytes. Therefore `written` must be valid UTF-8.
|
||||||
let written_str = unsafe { str::from_utf8_unchecked(written) };
|
let written_str = str::from_utf8(written).expect("must be valid UTF-8");
|
||||||
$serializer.serialize_str(written_str)
|
$serializer.serialize_str(written_str)
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
@@ -637,6 +819,53 @@ impl Serialize for net::IpAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
const DEC_DIGITS_LUT: &[u8] = b"\
|
||||||
|
0001020304050607080910111213141516171819\
|
||||||
|
2021222324252627282930313233343536373839\
|
||||||
|
4041424344454647484950515253545556575859\
|
||||||
|
6061626364656667686970717273747576777879\
|
||||||
|
8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[inline]
|
||||||
|
fn format_u8(mut n: u8, out: &mut [u8]) -> usize {
|
||||||
|
if n >= 100 {
|
||||||
|
let d1 = ((n % 100) << 1) as usize;
|
||||||
|
n /= 100;
|
||||||
|
out[0] = b'0' + n;
|
||||||
|
out[1] = DEC_DIGITS_LUT[d1];
|
||||||
|
out[2] = DEC_DIGITS_LUT[d1 + 1];
|
||||||
|
3
|
||||||
|
} else if n >= 10 {
|
||||||
|
let d1 = (n << 1) as usize;
|
||||||
|
out[0] = DEC_DIGITS_LUT[d1];
|
||||||
|
out[1] = DEC_DIGITS_LUT[d1 + 1];
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
out[0] = b'0' + n;
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[test]
|
||||||
|
fn test_format_u8() {
|
||||||
|
let mut i = 0u8;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut buf = [0u8; 3];
|
||||||
|
let written = format_u8(i, &mut buf);
|
||||||
|
assert_eq!(i.to_string().as_bytes(), &buf[..written]);
|
||||||
|
|
||||||
|
match i.checked_add(1) {
|
||||||
|
Some(next) => i = next,
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
@@ -645,7 +874,15 @@ impl Serialize for net::Ipv4Addr {
|
|||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
const MAX_LEN: usize = 15;
|
const MAX_LEN: usize = 15;
|
||||||
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
|
debug_assert_eq!(MAX_LEN, "101.102.103.104".len());
|
||||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
let mut buf = [b'.'; MAX_LEN];
|
||||||
|
let mut written = format_u8(self.octets()[0], &mut buf);
|
||||||
|
for oct in &self.octets()[1..] {
|
||||||
|
// Skip over delimiters that we initialized buf with
|
||||||
|
written += format_u8(*oct, &mut buf[written + 1..]) + 1;
|
||||||
|
}
|
||||||
|
// Safety: We've only written ASCII bytes to the buffer, so it is valid UTF-8
|
||||||
|
let buf = unsafe { str::from_utf8_unchecked(&buf[..written]) };
|
||||||
|
serializer.serialize_str(buf)
|
||||||
} else {
|
} else {
|
||||||
self.octets().serialize(serializer)
|
self.octets().serialize(serializer)
|
||||||
}
|
}
|
||||||
@@ -653,6 +890,7 @@ impl Serialize for net::Ipv4Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
@@ -669,6 +907,7 @@ impl Serialize for net::Ipv6Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
@@ -693,6 +932,7 @@ impl Serialize for net::SocketAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
@@ -709,16 +949,17 @@ impl Serialize for net::SocketAddrV4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
||||||
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
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
const MAX_LEN: usize = 47;
|
const MAX_LEN: usize = 58;
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
MAX_LEN,
|
MAX_LEN,
|
||||||
"[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len()
|
"[1001:1002:1003:1004:1005:1006:1007:1008%4294967295]:65000".len()
|
||||||
);
|
);
|
||||||
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
serialize_display_bounded_length!(self, MAX_LEN, serializer)
|
||||||
} else {
|
} else {
|
||||||
@@ -730,6 +971,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
|
||||||
@@ -743,6 +985,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
|
||||||
@@ -753,6 +996,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>
|
||||||
@@ -775,6 +1019,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
|
||||||
@@ -786,7 +1031,6 @@ impl Serialize for OsString {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl<T> Serialize for Wrapping<T>
|
impl<T> Serialize for Wrapping<T>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -799,3 +1043,70 @@ where
|
|||||||
self.0.serialize(serializer)
|
self.0.serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_core_num_saturating))]
|
||||||
|
impl<T> Serialize for Saturating<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.0.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Serialize for Reverse<T>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
self.0.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", not(no_std_atomic)))]
|
||||||
|
macro_rules! atomic_impl {
|
||||||
|
($($ty:ident $size:expr)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(any(no_target_has_atomic, target_has_atomic = $size))]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", target_has_atomic = $size))))]
|
||||||
|
impl Serialize for $ty {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
// Matches the atomic ordering used in libcore for the Debug impl
|
||||||
|
self.load(Ordering::Relaxed).serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", not(no_std_atomic)))]
|
||||||
|
atomic_impl! {
|
||||||
|
AtomicBool "8"
|
||||||
|
AtomicI8 "8"
|
||||||
|
AtomicI16 "16"
|
||||||
|
AtomicI32 "32"
|
||||||
|
AtomicIsize "ptr"
|
||||||
|
AtomicU8 "8"
|
||||||
|
AtomicU16 "16"
|
||||||
|
AtomicU32 "32"
|
||||||
|
AtomicUsize "ptr"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", not(no_std_atomic64)))]
|
||||||
|
atomic_impl! {
|
||||||
|
AtomicI64 "64"
|
||||||
|
AtomicU64 "64"
|
||||||
|
}
|
||||||
|
|||||||
+21
-26
@@ -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,12 +15,9 @@ use ser::{
|
|||||||
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
||||||
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```edition2021
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// #
|
|
||||||
/// # use serde::ser::{Serializer, Impossible};
|
/// # use serde::ser::{Serializer, Impossible};
|
||||||
/// # use serde::private::ser::Error;
|
/// # use serde::__private::doc::Error;
|
||||||
/// #
|
/// #
|
||||||
/// # struct MySerializer;
|
/// # struct MySerializer;
|
||||||
/// #
|
/// #
|
||||||
@@ -44,14 +41,12 @@ use ser::{
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// /* other Serializer methods */
|
/// /* other Serializer methods */
|
||||||
/// # __serialize_unimplemented! {
|
/// # serde::__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
|
||||||
/// # }
|
/// # }
|
||||||
/// }
|
/// }
|
||||||
/// #
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Serializer`]: trait.Serializer.html
|
/// [`Serializer`]: trait.Serializer.html
|
||||||
@@ -77,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 {}
|
||||||
@@ -97,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 {}
|
||||||
@@ -117,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 {}
|
||||||
@@ -137,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 {}
|
||||||
@@ -157,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 {}
|
||||||
@@ -185,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;
|
||||||
@@ -206,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;
|
||||||
|
|||||||
+192
-314
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
|||||||
|
use crate::lib::{Debug, Display};
|
||||||
|
|
||||||
|
/// Either a re-export of std::error::Error or a new identical trait, depending
|
||||||
|
/// on whether Serde's "std" feature is enabled.
|
||||||
|
///
|
||||||
|
/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require
|
||||||
|
/// [`std::error::Error`] as a supertrait, but only when Serde is built with
|
||||||
|
/// "std" enabled. Data formats that don't care about no\_std support should
|
||||||
|
/// generally provide their error types with a `std::error::Error` impl
|
||||||
|
/// directly:
|
||||||
|
///
|
||||||
|
/// ```edition2021
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// struct MySerError {...}
|
||||||
|
///
|
||||||
|
/// impl serde::ser::Error for MySerError {...}
|
||||||
|
///
|
||||||
|
/// impl std::fmt::Display for MySerError {...}
|
||||||
|
///
|
||||||
|
/// // We don't support no_std!
|
||||||
|
/// impl std::error::Error for MySerError {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Data formats that *do* support no\_std may either have a "std" feature of
|
||||||
|
/// their own:
|
||||||
|
///
|
||||||
|
/// ```toml
|
||||||
|
/// [features]
|
||||||
|
/// std = ["serde/std"]
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```edition2021
|
||||||
|
/// #[cfg(feature = "std")]
|
||||||
|
/// impl std::error::Error for MySerError {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ... or else provide the std Error impl unconditionally via Serde's
|
||||||
|
/// re-export:
|
||||||
|
///
|
||||||
|
/// ```edition2021
|
||||||
|
/// impl serde::ser::StdError for MySerError {}
|
||||||
|
/// ```
|
||||||
|
pub trait Error: Debug + Display {
|
||||||
|
/// The underlying cause of this error, if any.
|
||||||
|
fn source(&self) -> Option<&(Error + 'static)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-14
@@ -1,19 +1,18 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.81" # remember to update html_root_url
|
version = "1.0.209"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
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)]"
|
||||||
homepage = "https://serde.rs"
|
|
||||||
repository = "https://github.com/serde-rs/serde"
|
|
||||||
documentation = "https://serde.rs/derive.html"
|
documentation = "https://serde.rs/derive.html"
|
||||||
keywords = ["serde", "serialization", "no_std"]
|
edition = "2015"
|
||||||
|
exclude = ["build.rs"]
|
||||||
|
homepage = "https://serde.rs"
|
||||||
|
keywords = ["serde", "serialization", "no_std", "derive"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
readme = "crates-io.md"
|
readme = "crates-io.md"
|
||||||
include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
repository = "https://github.com/serde-rs/serde"
|
||||||
|
rust-version = "1.56"
|
||||||
[badges]
|
|
||||||
travis-ci = { repository = "serde-rs/serde" }
|
|
||||||
appveyor = { repository = "serde-rs/serde" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
@@ -24,9 +23,13 @@ name = "serde_derive"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "0.4"
|
proc-macro2 = { workspace = true, features = ["proc-macro"] }
|
||||||
quote = "0.6.3"
|
quote = { workspace = true, features = ["proc-macro"] }
|
||||||
syn = { version = "0.15.22", features = ["visit"] }
|
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]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
rustdoc-args = ["--generate-link-to-definition"]
|
||||||
|
|||||||
@@ -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)");
|
||||||
|
}
|
||||||
+126
-35
@@ -1,13 +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 syn::visit::{self, Visit};
|
|
||||||
|
|
||||||
use internals::ast::{Container, Data};
|
|
||||||
use internals::attr;
|
|
||||||
|
|
||||||
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
|
||||||
@@ -17,8 +13,8 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
|
|||||||
params: generics
|
params: generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| match *param {
|
.map(|param| match param {
|
||||||
syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam {
|
syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
|
||||||
eq_token: None,
|
eq_token: None,
|
||||||
default: None,
|
default: None,
|
||||||
..param.clone()
|
..param.clone()
|
||||||
@@ -50,8 +46,8 @@ pub fn with_where_predicates_from_fields(
|
|||||||
let predicates = cont
|
let predicates = cont
|
||||||
.data
|
.data
|
||||||
.all_fields()
|
.all_fields()
|
||||||
.flat_map(|field| from_field(&field.attrs))
|
.filter_map(|field| from_field(&field.attrs))
|
||||||
.flat_map(|predicates| predicates.to_vec());
|
.flat_map(<[syn::WherePredicate]>::to_vec);
|
||||||
|
|
||||||
let mut generics = generics.clone();
|
let mut generics = generics.clone();
|
||||||
generics.make_where_clause().predicates.extend(predicates);
|
generics.make_where_clause().predicates.extend(predicates);
|
||||||
@@ -63,8 +59,8 @@ pub fn with_where_predicates_from_variants(
|
|||||||
generics: &syn::Generics,
|
generics: &syn::Generics,
|
||||||
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
|
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
|
||||||
) -> syn::Generics {
|
) -> syn::Generics {
|
||||||
let variants = match cont.data {
|
let variants = match &cont.data {
|
||||||
Data::Enum(ref variants) => variants,
|
Data::Enum(variants) => variants,
|
||||||
Data::Struct(_, _) => {
|
Data::Struct(_, _) => {
|
||||||
return generics.clone();
|
return generics.clone();
|
||||||
}
|
}
|
||||||
@@ -72,8 +68,8 @@ pub fn with_where_predicates_from_variants(
|
|||||||
|
|
||||||
let predicates = variants
|
let predicates = variants
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|variant| from_variant(&variant.attrs))
|
.filter_map(|variant| from_variant(&variant.attrs))
|
||||||
.flat_map(|predicates| predicates.to_vec());
|
.flat_map(<[syn::WherePredicate]>::to_vec);
|
||||||
|
|
||||||
let mut generics = generics.clone();
|
let mut generics = generics.clone();
|
||||||
generics.make_where_clause().predicates.extend(predicates);
|
generics.make_where_clause().predicates.extend(predicates);
|
||||||
@@ -112,10 +108,11 @@ pub fn with_bound(
|
|||||||
// parameters.
|
// parameters.
|
||||||
associated_type_usage: Vec<&'ast syn::TypePath>,
|
associated_type_usage: Vec<&'ast syn::TypePath>,
|
||||||
}
|
}
|
||||||
impl<'ast> Visit<'ast> for FindTyParams<'ast> {
|
|
||||||
|
impl<'ast> FindTyParams<'ast> {
|
||||||
fn visit_field(&mut self, field: &'ast syn::Field) {
|
fn visit_field(&mut self, field: &'ast syn::Field) {
|
||||||
if let syn::Type::Path(ref ty) = field.ty {
|
if let syn::Type::Path(ty) = ungroup(&field.ty) {
|
||||||
if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() {
|
if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
|
||||||
if self.all_type_params.contains(&t.ident) {
|
if self.all_type_params.contains(&t.ident) {
|
||||||
self.associated_type_usage.push(ty);
|
self.associated_type_usage.push(ty);
|
||||||
}
|
}
|
||||||
@@ -126,7 +123,7 @@ pub fn with_bound(
|
|||||||
|
|
||||||
fn visit_path(&mut self, path: &'ast syn::Path) {
|
fn visit_path(&mut self, path: &'ast syn::Path) {
|
||||||
if let Some(seg) = path.segments.last() {
|
if let Some(seg) = path.segments.last() {
|
||||||
if seg.into_value().ident == "PhantomData" {
|
if seg.ident == "PhantomData" {
|
||||||
// Hardcoded exception, because PhantomData<T> implements
|
// Hardcoded exception, because PhantomData<T> implements
|
||||||
// Serialize and Deserialize whether or not T implements it.
|
// Serialize and Deserialize whether or not T implements it.
|
||||||
return;
|
return;
|
||||||
@@ -138,7 +135,101 @@ pub fn with_bound(
|
|||||||
self.relevant_type_params.insert(id.clone());
|
self.relevant_type_params.insert(id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit::visit_path(self, path);
|
for segment in &path.segments {
|
||||||
|
self.visit_path_segment(segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything below is simply traversing the syntax tree.
|
||||||
|
|
||||||
|
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
||||||
|
match ty {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::BareFn(ty) => {
|
||||||
|
for arg in &ty.inputs {
|
||||||
|
self.visit_type(&arg.ty);
|
||||||
|
}
|
||||||
|
self.visit_return_type(&ty.output);
|
||||||
|
}
|
||||||
|
syn::Type::Group(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::ImplTrait(ty) => {
|
||||||
|
for bound in &ty.bounds {
|
||||||
|
self.visit_type_param_bound(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
|
||||||
|
syn::Type::Paren(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::Path(ty) => {
|
||||||
|
if let Some(qself) = &ty.qself {
|
||||||
|
self.visit_type(&qself.ty);
|
||||||
|
}
|
||||||
|
self.visit_path(&ty.path);
|
||||||
|
}
|
||||||
|
syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::Reference(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::Slice(ty) => self.visit_type(&ty.elem),
|
||||||
|
syn::Type::TraitObject(ty) => {
|
||||||
|
for bound in &ty.bounds {
|
||||||
|
self.visit_type_param_bound(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::Type::Tuple(ty) => {
|
||||||
|
for elem in &ty.elems {
|
||||||
|
self.visit_type(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
|
||||||
|
self.visit_path_arguments(&segment.arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
|
||||||
|
match arguments {
|
||||||
|
syn::PathArguments::None => {}
|
||||||
|
syn::PathArguments::AngleBracketed(arguments) => {
|
||||||
|
for arg in &arguments.args {
|
||||||
|
match arg {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
||||||
|
syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty),
|
||||||
|
syn::GenericArgument::Lifetime(_)
|
||||||
|
| syn::GenericArgument::Const(_)
|
||||||
|
| syn::GenericArgument::AssocConst(_)
|
||||||
|
| syn::GenericArgument::Constraint(_) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::PathArguments::Parenthesized(arguments) => {
|
||||||
|
for argument in &arguments.inputs {
|
||||||
|
self.visit_type(argument);
|
||||||
|
}
|
||||||
|
self.visit_return_type(&arguments.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
|
||||||
|
match return_type {
|
||||||
|
syn::ReturnType::Default => {}
|
||||||
|
syn::ReturnType::Type(_, output) => self.visit_type(output),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
||||||
|
match bound {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
||||||
|
syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type parameter should not be considered used by a macro path.
|
// Type parameter should not be considered used by a macro path.
|
||||||
@@ -156,13 +247,13 @@ pub fn with_bound(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut visitor = FindTyParams {
|
let mut visitor = FindTyParams {
|
||||||
all_type_params: all_type_params,
|
all_type_params,
|
||||||
relevant_type_params: HashSet::new(),
|
relevant_type_params: HashSet::new(),
|
||||||
associated_type_usage: Vec::new(),
|
associated_type_usage: Vec::new(),
|
||||||
};
|
};
|
||||||
match cont.data {
|
match &cont.data {
|
||||||
Data::Enum(ref variants) => {
|
Data::Enum(variants) => {
|
||||||
for variant in variants.iter() {
|
for variant in variants {
|
||||||
let relevant_fields = variant
|
let relevant_fields = variant
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -172,7 +263,7 @@ pub fn with_bound(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(_, ref fields) => {
|
Data::Struct(_, fields) => {
|
||||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||||
visitor.visit_field(field.original);
|
visitor.visit_field(field.original);
|
||||||
}
|
}
|
||||||
@@ -245,7 +336,7 @@ pub fn with_self_bound(
|
|||||||
|
|
||||||
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
|
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
|
||||||
let bound = syn::Lifetime::new(lifetime, Span::call_site());
|
let bound = syn::Lifetime::new(lifetime, Span::call_site());
|
||||||
let def = syn::LifetimeDef {
|
let def = syn::LifetimeParam {
|
||||||
attrs: Vec::new(),
|
attrs: Vec::new(),
|
||||||
lifetime: bound.clone(),
|
lifetime: bound.clone(),
|
||||||
colon_token: None,
|
colon_token: None,
|
||||||
@@ -255,11 +346,11 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
|
|||||||
let params = Some(syn::GenericParam::Lifetime(def))
|
let params = Some(syn::GenericParam::Lifetime(def))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(generics.params.iter().cloned().map(|mut param| {
|
.chain(generics.params.iter().cloned().map(|mut param| {
|
||||||
match param {
|
match &mut param {
|
||||||
syn::GenericParam::Lifetime(ref mut param) => {
|
syn::GenericParam::Lifetime(param) => {
|
||||||
param.bounds.push(bound.clone());
|
param.bounds.push(bound.clone());
|
||||||
}
|
}
|
||||||
syn::GenericParam::Type(ref mut param) => {
|
syn::GenericParam::Type(param) => {
|
||||||
param
|
param
|
||||||
.bounds
|
.bounds
|
||||||
.push(syn::TypeParamBound::Lifetime(bound.clone()));
|
.push(syn::TypeParamBound::Lifetime(bound.clone()));
|
||||||
@@ -271,7 +362,7 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
syn::Generics {
|
syn::Generics {
|
||||||
params: params,
|
params,
|
||||||
..generics.clone()
|
..generics.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,14 +382,14 @@ fn type_of_item(cont: &Container) -> syn::Type {
|
|||||||
.generics
|
.generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|param| match *param {
|
.map(|param| match param {
|
||||||
syn::GenericParam::Type(ref param) => {
|
syn::GenericParam::Type(param) => {
|
||||||
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
||||||
qself: None,
|
qself: None,
|
||||||
path: param.ident.clone().into(),
|
path: param.ident.clone().into(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
syn::GenericParam::Lifetime(ref param) => {
|
syn::GenericParam::Lifetime(param) => {
|
||||||
syn::GenericArgument::Lifetime(param.lifetime.clone())
|
syn::GenericArgument::Lifetime(param.lifetime.clone())
|
||||||
}
|
}
|
||||||
syn::GenericParam::Const(_) => {
|
syn::GenericParam::Const(_) => {
|
||||||
|
|||||||
+1177
-989
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
|
||||||
|
let use_serde = match serde_path {
|
||||||
|
Some(path) => quote! {
|
||||||
|
use #path as _serde;
|
||||||
|
},
|
||||||
|
None => quote! {
|
||||||
|
#[allow(unused_extern_crates, clippy::useless_attribute)]
|
||||||
|
extern crate serde as _serde;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||||
|
const _: () = {
|
||||||
|
#use_serde
|
||||||
|
#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.
|
||||||
@@ -27,9 +27,9 @@ macro_rules! quote_block {
|
|||||||
pub struct Expr(pub Fragment);
|
pub struct Expr(pub Fragment);
|
||||||
impl ToTokens for Expr {
|
impl ToTokens for Expr {
|
||||||
fn to_tokens(&self, out: &mut TokenStream) {
|
fn to_tokens(&self, out: &mut TokenStream) {
|
||||||
match self.0 {
|
match &self.0 {
|
||||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
Fragment::Expr(expr) => expr.to_tokens(out),
|
||||||
Fragment::Block(ref block) => {
|
Fragment::Block(block) => {
|
||||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,9 +40,9 @@ impl ToTokens for Expr {
|
|||||||
pub struct Stmts(pub Fragment);
|
pub struct Stmts(pub Fragment);
|
||||||
impl ToTokens for Stmts {
|
impl ToTokens for Stmts {
|
||||||
fn to_tokens(&self, out: &mut TokenStream) {
|
fn to_tokens(&self, out: &mut TokenStream) {
|
||||||
match self.0 {
|
match &self.0 {
|
||||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
Fragment::Expr(expr) => expr.to_tokens(out),
|
||||||
Fragment::Block(ref block) => block.to_tokens(out),
|
Fragment::Block(block) => block.to_tokens(out),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,12 +52,12 @@ impl ToTokens for Stmts {
|
|||||||
pub struct Match(pub Fragment);
|
pub struct Match(pub Fragment);
|
||||||
impl ToTokens for Match {
|
impl ToTokens for Match {
|
||||||
fn to_tokens(&self, out: &mut TokenStream) {
|
fn to_tokens(&self, out: &mut TokenStream) {
|
||||||
match self.0 {
|
match &self.0 {
|
||||||
Fragment::Expr(ref expr) => {
|
Fragment::Expr(expr) => {
|
||||||
expr.to_tokens(out);
|
expr.to_tokens(out);
|
||||||
<Token![,]>::default().to_tokens(out);
|
<Token![,]>::default().to_tokens(out);
|
||||||
}
|
}
|
||||||
Fragment::Block(ref block) => {
|
Fragment::Block(block) => {
|
||||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,9 +66,9 @@ impl ToTokens for Match {
|
|||||||
|
|
||||||
impl AsRef<TokenStream> for Fragment {
|
impl AsRef<TokenStream> for Fragment {
|
||||||
fn as_ref(&self) -> &TokenStream {
|
fn as_ref(&self) -> &TokenStream {
|
||||||
match *self {
|
match self {
|
||||||
Fragment::Expr(ref expr) => expr,
|
Fragment::Expr(expr) => expr,
|
||||||
Fragment::Block(ref block) => block,
|
Fragment::Block(block) => block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
//! 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 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.
|
||||||
@@ -23,7 +21,7 @@ pub struct Container<'a> {
|
|||||||
|
|
||||||
/// The fields of a struct or enum.
|
/// The fields of a struct or enum.
|
||||||
///
|
///
|
||||||
/// Analagous to `syn::Data`.
|
/// Analogous to `syn::Data`.
|
||||||
pub enum Data<'a> {
|
pub enum Data<'a> {
|
||||||
Enum(Vec<Variant<'a>>),
|
Enum(Vec<Variant<'a>>),
|
||||||
Struct(Style, Vec<Field<'a>>),
|
Struct(Style, Vec<Field<'a>>),
|
||||||
@@ -60,14 +58,16 @@ pub enum Style {
|
|||||||
|
|
||||||
impl<'a> Container<'a> {
|
impl<'a> Container<'a> {
|
||||||
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
|
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
|
||||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Option<Container<'a>> {
|
pub fn from_ast(
|
||||||
let mut attrs = attr::Container::from_ast(cx, item);
|
cx: &Ctxt,
|
||||||
|
item: &'a syn::DeriveInput,
|
||||||
|
derive: Derive,
|
||||||
|
) -> Option<Container<'a>> {
|
||||||
|
let attrs = attr::Container::from_ast(cx, item);
|
||||||
|
|
||||||
let mut data = match item.data {
|
let mut data = match &item.data {
|
||||||
syn::Data::Enum(ref data) => {
|
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
|
||||||
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default()))
|
syn::Data::Struct(data) => {
|
||||||
}
|
|
||||||
syn::Data::Struct(ref 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());
|
||||||
Data::Struct(style, fields)
|
Data::Struct(style, fields)
|
||||||
}
|
}
|
||||||
@@ -77,37 +77,31 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut has_flatten = false;
|
match &mut data {
|
||||||
match data {
|
Data::Enum(variants) => {
|
||||||
Data::Enum(ref mut variants) => {
|
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
variant.attrs.rename_by_rule(attrs.rename_all());
|
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.attrs.rename_by_rule(variant.attrs.rename_all());
|
.rename_all_rules()
|
||||||
|
.or(attrs.rename_all_fields_rules()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(_, ref mut fields) => {
|
Data::Struct(_, fields) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if field.attrs.flatten() {
|
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||||
has_flatten = true;
|
|
||||||
}
|
|
||||||
field.attrs.rename_by_rule(attrs.rename_all());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
attrs,
|
||||||
data: data,
|
data,
|
||||||
generics: &item.generics,
|
generics: &item.generics,
|
||||||
original: item,
|
original: item,
|
||||||
};
|
};
|
||||||
@@ -117,12 +111,12 @@ 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(ref variants) => {
|
Data::Enum(variants) => {
|
||||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||||
}
|
}
|
||||||
Data::Struct(_, ref fields) => Box::new(fields.iter()),
|
Data::Struct(_, fields) => Box::new(fields.iter()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +130,7 @@ fn enum_from_ast<'a>(
|
|||||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||||
container_default: &attr::Default,
|
container_default: &attr::Default,
|
||||||
) -> Vec<Variant<'a>> {
|
) -> Vec<Variant<'a>> {
|
||||||
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);
|
||||||
@@ -144,13 +138,26 @@ fn enum_from_ast<'a>(
|
|||||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||||
Variant {
|
Variant {
|
||||||
ident: variant.ident.clone(),
|
ident: variant.ident.clone(),
|
||||||
attrs: attrs,
|
attrs,
|
||||||
style: style,
|
style,
|
||||||
fields: fields,
|
fields,
|
||||||
original: variant,
|
original: variant,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
let index_of_last_tagged_variant = variants
|
||||||
|
.iter()
|
||||||
|
.rposition(|variant| !variant.attrs.untagged());
|
||||||
|
if let Some(index_of_last_tagged_variant) = index_of_last_tagged_variant {
|
||||||
|
for variant in &variants[..index_of_last_tagged_variant] {
|
||||||
|
if variant.attrs.untagged() {
|
||||||
|
cx.error_spanned_by(&variant.ident, "all variants with the #[serde(untagged)] attribute must be placed at the end of the enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variants
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_from_ast<'a>(
|
fn struct_from_ast<'a>(
|
||||||
@@ -159,16 +166,16 @@ fn struct_from_ast<'a>(
|
|||||||
attrs: Option<&attr::Variant>,
|
attrs: Option<&attr::Variant>,
|
||||||
container_default: &attr::Default,
|
container_default: &attr::Default,
|
||||||
) -> (Style, Vec<Field<'a>>) {
|
) -> (Style, Vec<Field<'a>>) {
|
||||||
match *fields {
|
match fields {
|
||||||
syn::Fields::Named(ref 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),
|
||||||
),
|
),
|
||||||
syn::Fields::Unnamed(ref 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),
|
||||||
),
|
),
|
||||||
syn::Fields::Unnamed(ref 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),
|
||||||
),
|
),
|
||||||
@@ -186,8 +193,8 @@ fn fields_from_ast<'a>(
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, field)| Field {
|
.map(|(i, field)| Field {
|
||||||
member: match field.ident {
|
member: match &field.ident {
|
||||||
Some(ref 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),
|
||||||
|
|||||||
+1093
-922
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,18 @@
|
|||||||
//! 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::str::FromStr;
|
|
||||||
|
|
||||||
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(PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum RenameRule {
|
pub enum RenameRule {
|
||||||
/// Don't apply a default rename rule.
|
/// Don't apply a default rename rule.
|
||||||
None,
|
None,
|
||||||
/// Rename direct children to "lowercase" style.
|
/// Rename direct children to "lowercase" style.
|
||||||
LowerCase,
|
LowerCase,
|
||||||
/// Rename direct children to "UPPERCASE" style.
|
/// Rename direct children to "UPPERCASE" style.
|
||||||
UPPERCASE,
|
UpperCase,
|
||||||
/// Rename direct children to "PascalCase" style, as typically used for
|
/// Rename direct children to "PascalCase" style, as typically used for
|
||||||
/// enum variants.
|
/// enum variants.
|
||||||
PascalCase,
|
PascalCase,
|
||||||
@@ -35,13 +30,35 @@ pub enum RenameRule {
|
|||||||
ScreamingKebabCase,
|
ScreamingKebabCase,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RENAME_RULES: &[(&str, RenameRule)] = &[
|
||||||
|
("lowercase", LowerCase),
|
||||||
|
("UPPERCASE", UpperCase),
|
||||||
|
("PascalCase", PascalCase),
|
||||||
|
("camelCase", CamelCase),
|
||||||
|
("snake_case", SnakeCase),
|
||||||
|
("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
|
||||||
|
("kebab-case", KebabCase),
|
||||||
|
("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
|
||||||
|
];
|
||||||
|
|
||||||
impl RenameRule {
|
impl RenameRule {
|
||||||
|
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
|
||||||
|
for (name, rule) in RENAME_RULES {
|
||||||
|
if rename_all_str == *name {
|
||||||
|
return Ok(*rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ParseError {
|
||||||
|
unknown: rename_all_str,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// 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(),
|
||||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||||
SnakeCase => {
|
SnakeCase => {
|
||||||
let mut snake = String::new();
|
let mut snake = String::new();
|
||||||
@@ -62,10 +79,10 @@ 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 => {
|
||||||
let mut pascal = String::new();
|
let mut pascal = String::new();
|
||||||
let mut capitalize = true;
|
let mut capitalize = true;
|
||||||
@@ -90,23 +107,32 @@ 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for RenameRule {
|
pub struct ParseError<'a> {
|
||||||
type Err = ();
|
unknown: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
impl<'a> Display for ParseError<'a> {
|
||||||
match rename_all_str {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
"lowercase" => Ok(LowerCase),
|
f.write_str("unknown rename rule `rename_all = ")?;
|
||||||
"UPPERCASE" => Ok(UPPERCASE),
|
Debug::fmt(self.unknown, f)?;
|
||||||
"PascalCase" => Ok(PascalCase),
|
f.write_str("`, expected one of ")?;
|
||||||
"camelCase" => Ok(CamelCase),
|
for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() {
|
||||||
"snake_case" => Ok(SnakeCase),
|
if i > 0 {
|
||||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
f.write_str(", ")?;
|
||||||
"kebab-case" => Ok(KebabCase),
|
}
|
||||||
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
Debug::fmt(name, f)?;
|
||||||
_ => Err(()),
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +157,7 @@ fn rename_variants() {
|
|||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_variant(original), original);
|
assert_eq!(None.apply_to_variant(original), original);
|
||||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||||
assert_eq!(UPPERCASE.apply_to_variant(original), upper);
|
assert_eq!(UpperCase.apply_to_variant(original), upper);
|
||||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||||
@@ -163,7 +189,7 @@ fn rename_fields() {
|
|||||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||||
] {
|
] {
|
||||||
assert_eq!(None.apply_to_field(original), original);
|
assert_eq!(None.apply_to_field(original), original);
|
||||||
assert_eq!(UPPERCASE.apply_to_field(original), upper);
|
assert_eq!(UpperCase.apply_to_field(original), upper);
|
||||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||||
|
|||||||
+187
-115
@@ -1,11 +1,13 @@
|
|||||||
use internals::ast::{Container, Data, Field, Style};
|
use crate::internals::ast::{Container, Data, Field, Style};
|
||||||
use internals::attr::{EnumTag, Identifier};
|
use crate::internals::attr::{Default, Identifier, TagType};
|
||||||
use internals::{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
|
// Cross-cutting checks that require looking at more than a single attrs object.
|
||||||
/// 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_getter(cx, cont);
|
check_getter(cx, cont);
|
||||||
check_flatten(cx, cont);
|
check_flatten(cx, cont);
|
||||||
check_identifier(cx, cont);
|
check_identifier(cx, cont);
|
||||||
@@ -13,10 +15,66 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
check_internal_tag_field_name_conflict(cx, cont);
|
check_internal_tag_field_name_conflict(cx, cont);
|
||||||
check_adjacent_tag_conflict(cx, cont);
|
check_adjacent_tag_conflict(cx, cont);
|
||||||
check_transparent(cx, cont, derive);
|
check_transparent(cx, cont, derive);
|
||||||
|
check_from_and_try_from(cx, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
// If some field of a tuple struct is marked #[serde(default)] then all fields
|
||||||
/// attribute.
|
// 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 type:
|
||||||
|
//
|
||||||
|
// #[serde(remote = "Generic")]
|
||||||
|
// struct Generic<T> {…}
|
||||||
|
//
|
||||||
|
// or none of them, i.e. defining impls for one concrete instantiation of the
|
||||||
|
// remote type only:
|
||||||
|
//
|
||||||
|
// #[serde(remote = "Generic<T>")]
|
||||||
|
// struct ConcreteDef {…}
|
||||||
|
//
|
||||||
|
fn check_remote_generic(cx: &Ctxt, cont: &Container) {
|
||||||
|
if let Some(remote) = cont.attrs.remote() {
|
||||||
|
let local_has_generic = !cont.generics.params.is_empty();
|
||||||
|
let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none();
|
||||||
|
if local_has_generic && remote_has_generic {
|
||||||
|
cx.error_spanned_by(remote, "remove generic parameters from this path");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters are only allowed inside structs (not enums) with the `remote`
|
||||||
|
// attribute.
|
||||||
fn check_getter(cx: &Ctxt, cont: &Container) {
|
fn check_getter(cx: &Ctxt, cont: &Container) {
|
||||||
match cont.data {
|
match cont.data {
|
||||||
Data::Enum(_) => {
|
Data::Enum(_) => {
|
||||||
@@ -31,27 +89,26 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
|
|||||||
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
cont.original,
|
cont.original,
|
||||||
"#[serde(getter = \"...\")] can only be used in structs \
|
"#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]",
|
||||||
that have #[serde(remote = \"...\")]",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flattening has some restrictions we can test.
|
// Flattening has some restrictions we can test.
|
||||||
fn check_flatten(cx: &Ctxt, cont: &Container) {
|
fn check_flatten(cx: &Ctxt, cont: &Container) {
|
||||||
match cont.data {
|
match &cont.data {
|
||||||
Data::Enum(ref variants) => {
|
Data::Enum(variants) => {
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
for field in &variant.fields {
|
for field in &variant.fields {
|
||||||
check_flatten_field(cx, variant.style, field);
|
check_flatten_field(cx, variant.style, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(style, ref fields) => {
|
Data::Struct(style, fields) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
check_flatten_field(cx, style, field);
|
check_flatten_field(cx, *style, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,39 +133,18 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if field.attrs.skip_serializing() {
|
|
||||||
cx.error_spanned_by(
|
|
||||||
field.original,
|
|
||||||
"#[serde(flatten)] can not be combined with \
|
|
||||||
#[serde(skip_serializing)]",
|
|
||||||
);
|
|
||||||
} else if field.attrs.skip_serializing_if().is_some() {
|
|
||||||
cx.error_spanned_by(
|
|
||||||
field.original,
|
|
||||||
"#[serde(flatten)] can not be combined with \
|
|
||||||
#[serde(skip_serializing_if = \"...\")]",
|
|
||||||
);
|
|
||||||
} else if field.attrs.skip_deserializing() {
|
|
||||||
cx.error_spanned_by(
|
|
||||||
field.original,
|
|
||||||
"#[serde(flatten)] can not be combined with \
|
|
||||||
#[serde(skip_deserializing)]",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `other` attribute must be used at most once and it must be the last
|
// The `other` attribute must be used at most once and it must be the last
|
||||||
/// variant of an enum.
|
// variant of an enum.
|
||||||
///
|
//
|
||||||
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
|
// Inside a `variant_identifier` all variants must be unit variants. Inside a
|
||||||
/// `field_identifier` all but possibly one variant must be unit variants. The
|
// `field_identifier` all but possibly one variant must be unit variants. The
|
||||||
/// last variant may be a newtype variant which is an implicit "other" case.
|
// last variant may be a newtype variant which is an implicit "other" case.
|
||||||
fn check_identifier(cx: &Ctxt, cont: &Container) {
|
fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||||
let variants = match cont.data {
|
let variants = match &cont.data {
|
||||||
Data::Enum(ref variants) => variants,
|
Data::Enum(variants) => variants,
|
||||||
Data::Struct(_, _) => {
|
Data::Struct(_, _) => return,
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, variant) in variants.iter().enumerate() {
|
for (i, variant) in variants.iter().enumerate() {
|
||||||
@@ -127,7 +163,7 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Variant with `other` attribute cannot appear in untagged enum
|
// Variant with `other` attribute cannot appear in untagged enum
|
||||||
(_, Identifier::No, true, &EnumTag::None) => {
|
(_, Identifier::No, true, &TagType::None) => {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
variant.original,
|
variant.original,
|
||||||
"#[serde(other)] cannot appear on untagged enum",
|
"#[serde(other)] cannot appear on untagged enum",
|
||||||
@@ -185,105 +221,125 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
// Skip-(de)serializing attributes are not allowed on variants marked
|
||||||
/// (de)serialize_with.
|
// (de)serialize_with.
|
||||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||||
let variants = match cont.data {
|
let variants = match &cont.data {
|
||||||
Data::Enum(ref variants) => variants,
|
Data::Enum(variants) => variants,
|
||||||
Data::Struct(_, _) => {
|
Data::Struct(_, _) => return,
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for variant in variants.iter() {
|
for variant in variants {
|
||||||
if variant.attrs.serialize_with().is_some() {
|
if variant.attrs.serialize_with().is_some() {
|
||||||
if variant.attrs.skip_serializing() {
|
if variant.attrs.skip_serializing() {
|
||||||
cx.error_spanned_by(variant.original, format!(
|
cx.error_spanned_by(
|
||||||
"variant `{}` cannot have both #[serde(serialize_with)] and \
|
variant.original,
|
||||||
#[serde(skip_serializing)]",
|
format!(
|
||||||
variant.ident
|
"variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]",
|
||||||
));
|
variant.ident
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for field in &variant.fields {
|
for field in &variant.fields {
|
||||||
let member = member_message(&field.member);
|
let member = member_message(&field.member);
|
||||||
|
|
||||||
if field.attrs.skip_serializing() {
|
if field.attrs.skip_serializing() {
|
||||||
cx.error_spanned_by(variant.original, format!(
|
cx.error_spanned_by(
|
||||||
"variant `{}` cannot have both #[serde(serialize_with)] and \
|
variant.original,
|
||||||
a field {} marked with #[serde(skip_serializing)]",
|
format!(
|
||||||
variant.ident, member
|
"variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]",
|
||||||
));
|
variant.ident, member
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.attrs.skip_serializing_if().is_some() {
|
if field.attrs.skip_serializing_if().is_some() {
|
||||||
cx.error_spanned_by(variant.original, format!(
|
cx.error_spanned_by(
|
||||||
"variant `{}` cannot have both #[serde(serialize_with)] and \
|
variant.original,
|
||||||
a field {} marked with #[serde(skip_serializing_if)]",
|
format!(
|
||||||
variant.ident, member
|
"variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]",
|
||||||
));
|
variant.ident, member
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if variant.attrs.deserialize_with().is_some() {
|
if variant.attrs.deserialize_with().is_some() {
|
||||||
if variant.attrs.skip_deserializing() {
|
if variant.attrs.skip_deserializing() {
|
||||||
cx.error_spanned_by(variant.original, format!(
|
cx.error_spanned_by(
|
||||||
"variant `{}` cannot have both #[serde(deserialize_with)] and \
|
variant.original,
|
||||||
#[serde(skip_deserializing)]",
|
format!(
|
||||||
variant.ident
|
"variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]",
|
||||||
));
|
variant.ident
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for field in &variant.fields {
|
for field in &variant.fields {
|
||||||
if field.attrs.skip_deserializing() {
|
if field.attrs.skip_deserializing() {
|
||||||
let member = member_message(&field.member);
|
let member = member_message(&field.member);
|
||||||
|
|
||||||
cx.error_spanned_by(variant.original, format!(
|
cx.error_spanned_by(
|
||||||
"variant `{}` cannot have both #[serde(deserialize_with)] \
|
variant.original,
|
||||||
and a field {} marked with #[serde(skip_deserializing)]",
|
format!(
|
||||||
variant.ident, member
|
"variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]",
|
||||||
));
|
variant.ident, member
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The tag of an internally-tagged struct variant must not be
|
// The tag of an internally-tagged struct variant must not be the same as either
|
||||||
/// the same as either one of its fields, as this would result in
|
// one of its fields, as this would result in duplicate keys in the serialized
|
||||||
/// duplicate keys in the serialized output and/or ambiguity in
|
// output and/or ambiguity in the to-be-deserialized input.
|
||||||
/// the to-be-deserialized input.
|
|
||||||
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
||||||
let variants = match cont.data {
|
let variants = match &cont.data {
|
||||||
Data::Enum(ref variants) => variants,
|
Data::Enum(variants) => variants,
|
||||||
Data::Struct(_, _) => return,
|
Data::Struct(_, _) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let tag = match *cont.attrs.tag() {
|
let tag = match cont.attrs.tag() {
|
||||||
EnumTag::Internal { ref tag } => tag.as_str(),
|
TagType::Internal { tag } => tag.as_str(),
|
||||||
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
|
TagType::External | TagType::Adjacent { .. } | TagType::None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let diagnose_conflict = || cx.error_spanned_by(
|
let diagnose_conflict = || {
|
||||||
cont.original,
|
cx.error_spanned_by(
|
||||||
format!("variant field name `{}` conflicts with internal tag", tag),
|
cont.original,
|
||||||
);
|
format!("variant field name `{}` conflicts with internal tag", tag),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
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();
|
||||||
let de_name = name.deserialize_name();
|
|
||||||
|
|
||||||
if check_ser && ser_name == tag || check_de && de_name == tag {
|
if check_ser && ser_name == tag {
|
||||||
diagnose_conflict();
|
diagnose_conflict();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for de_name in field.attrs.aliases() {
|
||||||
|
if check_de && de_name == tag {
|
||||||
|
diagnose_conflict();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Unit | Style::Newtype | Style::Tuple => {}
|
Style::Unit | Style::Newtype | Style::Tuple => {}
|
||||||
@@ -291,26 +347,26 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In the case of adjacently-tagged enums, the type and the
|
// In the case of adjacently-tagged enums, the type and the contents tag must
|
||||||
/// contents tag must differ, for the same reason.
|
// differ, for the same reason.
|
||||||
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
|
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
|
||||||
let (type_tag, content_tag) = match *cont.attrs.tag() {
|
let (type_tag, content_tag) = match cont.attrs.tag() {
|
||||||
EnumTag::Adjacent {
|
TagType::Adjacent { tag, content } => (tag, content),
|
||||||
ref tag,
|
TagType::Internal { .. } | TagType::External | TagType::None => return,
|
||||||
ref content,
|
|
||||||
} => (tag, content),
|
|
||||||
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if type_tag == content_tag {
|
if type_tag == content_tag {
|
||||||
cx.error_spanned_by(cont.original, format!(
|
cx.error_spanned_by(
|
||||||
"enum tags `{}` for type and content conflict with each other",
|
cont.original,
|
||||||
type_tag
|
format!(
|
||||||
));
|
"enum tags `{}` for type and content conflict with each other",
|
||||||
|
type_tag
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enums and unit structs cannot be transparent.
|
// Enums and unit structs cannot be transparent.
|
||||||
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
||||||
if !cont.attrs.transparent() {
|
if !cont.attrs.transparent() {
|
||||||
return;
|
return;
|
||||||
@@ -323,6 +379,13 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cont.attrs.type_try_from().is_some() {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if cont.attrs.type_into().is_some() {
|
if cont.attrs.type_into().is_some() {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
cont.original,
|
cont.original,
|
||||||
@@ -330,7 +393,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = match cont.data {
|
let fields = match &mut cont.data {
|
||||||
Data::Enum(_) => {
|
Data::Enum(_) => {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
cont.original,
|
cont.original,
|
||||||
@@ -345,7 +408,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Data::Struct(_, ref mut fields) => fields,
|
Data::Struct(_, fields) => fields,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut transparent_field = None;
|
let mut transparent_field = None;
|
||||||
@@ -383,16 +446,16 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn member_message(member: &Member) -> String {
|
fn member_message(member: &Member) -> String {
|
||||||
match *member {
|
match member {
|
||||||
Member::Named(ref ident) => format!("`{}`", ident),
|
Member::Named(ident) => format!("`{}`", ident),
|
||||||
Member::Unnamed(ref i) => format!("#{}", i.index),
|
Member::Unnamed(i) => format!("#{}", i.index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allow_transparent(field: &Field, derive: Derive) -> bool {
|
fn allow_transparent(field: &Field, derive: Derive) -> bool {
|
||||||
if let Type::Path(ref ty) = *field.ty {
|
if let Type::Path(ty) = ungroup(field.ty) {
|
||||||
if let Some(seg) = ty.path.segments.last() {
|
if let Some(seg) = ty.path.segments.last() {
|
||||||
if seg.into_value().ident == "PhantomData" {
|
if seg.ident == "PhantomData" {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,3 +466,12 @@ fn allow_transparent(field: &Field, derive: Derive) -> bool {
|
|||||||
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
|
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
|
||||||
|
if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
///
|
///
|
||||||
@@ -38,13 +37,25 @@ impl Ctxt {
|
|||||||
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add one of Syn's parse errors.
|
||||||
|
pub fn syn_error(&self, err: syn::Error) {
|
||||||
|
self.errors.borrow_mut().as_mut().unwrap().push(err);
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume this object, producing a formatted error string if there are errors.
|
/// Consume this object, producing a formatted error string if there are errors.
|
||||||
pub fn check(self) -> Result<(), Vec<syn::Error>> {
|
pub fn check(self) -> syn::Result<()> {
|
||||||
let errors = self.errors.borrow_mut().take().unwrap();
|
let mut errors = self.errors.borrow_mut().take().unwrap().into_iter();
|
||||||
match errors.len() {
|
|
||||||
0 => Ok(()),
|
let mut combined = match errors.next() {
|
||||||
_ => Err(errors),
|
Some(first) => first,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
for rest in errors {
|
||||||
|
combined.combine(rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(combined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
|
||||||
mod ctxt;
|
|
||||||
pub use self::ctxt::Ctxt;
|
|
||||||
|
|
||||||
mod case;
|
mod case;
|
||||||
mod check;
|
mod check;
|
||||||
|
mod ctxt;
|
||||||
|
mod receiver;
|
||||||
|
mod respan;
|
||||||
|
mod symbol;
|
||||||
|
|
||||||
|
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,
|
||||||
Deserialize,
|
Deserialize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ungroup(mut ty: &Type) -> &Type {
|
||||||
|
while let Type::Group(group) = ty {
|
||||||
|
ty = &group.elem;
|
||||||
|
}
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,292 @@
|
|||||||
|
use crate::internals::respan::respan;
|
||||||
|
use proc_macro2::Span;
|
||||||
|
use quote::ToTokens;
|
||||||
|
use std::mem;
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::{
|
||||||
|
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
|
||||||
|
Path, PathArguments, QSelf, ReturnType, Token, Type, TypeParamBound, TypePath, WherePredicate,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn replace_receiver(input: &mut DeriveInput) {
|
||||||
|
let self_ty = {
|
||||||
|
let ident = &input.ident;
|
||||||
|
let ty_generics = input.generics.split_for_impl().1;
|
||||||
|
parse_quote!(#ident #ty_generics)
|
||||||
|
};
|
||||||
|
let mut visitor = ReplaceReceiver(&self_ty);
|
||||||
|
visitor.visit_generics_mut(&mut input.generics);
|
||||||
|
visitor.visit_data_mut(&mut input.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReplaceReceiver<'a>(&'a TypePath);
|
||||||
|
|
||||||
|
impl ReplaceReceiver<'_> {
|
||||||
|
fn self_ty(&self, span: Span) -> TypePath {
|
||||||
|
let tokens = self.0.to_token_stream();
|
||||||
|
let respanned = respan(tokens, span);
|
||||||
|
syn::parse2(respanned).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
|
||||||
|
if path.leading_colon.is_some() || path.segments[0].ident != "Self" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.segments.len() == 1 {
|
||||||
|
self.self_to_expr_path(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let span = path.segments[0].ident.span();
|
||||||
|
*qself = Some(QSelf {
|
||||||
|
lt_token: Token,
|
||||||
|
ty: Box::new(Type::Path(self.self_ty(span))),
|
||||||
|
position: 0,
|
||||||
|
as_token: None,
|
||||||
|
gt_token: Token,
|
||||||
|
});
|
||||||
|
|
||||||
|
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
|
||||||
|
|
||||||
|
let segments = mem::replace(&mut path.segments, Punctuated::new());
|
||||||
|
path.segments = segments.into_pairs().skip(1).collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn self_to_expr_path(&self, path: &mut Path) {
|
||||||
|
let self_ty = self.self_ty(path.segments[0].ident.span());
|
||||||
|
let variant = mem::replace(path, self_ty.path);
|
||||||
|
for segment in &mut path.segments {
|
||||||
|
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
|
||||||
|
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
|
||||||
|
bracketed.colon2_token = Some(<Token![::]>::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if variant.segments.len() > 1 {
|
||||||
|
path.segments.push_punct(<Token![::]>::default());
|
||||||
|
path.segments.extend(variant.segments.into_pairs().skip(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReplaceReceiver<'_> {
|
||||||
|
// `Self` -> `Receiver`
|
||||||
|
fn visit_type_mut(&mut self, ty: &mut Type) {
|
||||||
|
let span = if let Type::Path(node) = ty {
|
||||||
|
if node.qself.is_none() && node.path.is_ident("Self") {
|
||||||
|
node.path.segments[0].ident.span()
|
||||||
|
} else {
|
||||||
|
self.visit_type_path_mut(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.visit_type_mut_impl(ty);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
*ty = Type::Path(self.self_ty(span));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Self::Assoc` -> `<Receiver>::Assoc`
|
||||||
|
fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
|
||||||
|
if ty.qself.is_none() {
|
||||||
|
self.self_to_qself(&mut ty.qself, &mut ty.path);
|
||||||
|
}
|
||||||
|
self.visit_type_path_mut_impl(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Self::method` -> `<Receiver>::method`
|
||||||
|
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
|
||||||
|
if expr.qself.is_none() {
|
||||||
|
self.self_to_qself(&mut expr.qself, &mut expr.path);
|
||||||
|
}
|
||||||
|
self.visit_expr_path_mut_impl(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything below is simply traversing the syntax tree.
|
||||||
|
|
||||||
|
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
|
||||||
|
match ty {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
Type::Array(ty) => {
|
||||||
|
self.visit_type_mut(&mut ty.elem);
|
||||||
|
self.visit_expr_mut(&mut ty.len);
|
||||||
|
}
|
||||||
|
Type::BareFn(ty) => {
|
||||||
|
for arg in &mut ty.inputs {
|
||||||
|
self.visit_type_mut(&mut arg.ty);
|
||||||
|
}
|
||||||
|
self.visit_return_type_mut(&mut ty.output);
|
||||||
|
}
|
||||||
|
Type::Group(ty) => self.visit_type_mut(&mut ty.elem),
|
||||||
|
Type::ImplTrait(ty) => {
|
||||||
|
for bound in &mut ty.bounds {
|
||||||
|
self.visit_type_param_bound_mut(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac),
|
||||||
|
Type::Paren(ty) => self.visit_type_mut(&mut ty.elem),
|
||||||
|
Type::Path(ty) => {
|
||||||
|
if let Some(qself) = &mut ty.qself {
|
||||||
|
self.visit_type_mut(&mut qself.ty);
|
||||||
|
}
|
||||||
|
self.visit_path_mut(&mut ty.path);
|
||||||
|
}
|
||||||
|
Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem),
|
||||||
|
Type::Reference(ty) => self.visit_type_mut(&mut ty.elem),
|
||||||
|
Type::Slice(ty) => self.visit_type_mut(&mut ty.elem),
|
||||||
|
Type::TraitObject(ty) => {
|
||||||
|
for bound in &mut ty.bounds {
|
||||||
|
self.visit_type_param_bound_mut(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Tuple(ty) => {
|
||||||
|
for elem in &mut ty.elems {
|
||||||
|
self.visit_type_mut(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) {
|
||||||
|
if let Some(qself) = &mut ty.qself {
|
||||||
|
self.visit_type_mut(&mut qself.ty);
|
||||||
|
}
|
||||||
|
self.visit_path_mut(&mut ty.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) {
|
||||||
|
if let Some(qself) = &mut expr.qself {
|
||||||
|
self.visit_type_mut(&mut qself.ty);
|
||||||
|
}
|
||||||
|
self.visit_path_mut(&mut expr.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_path_mut(&mut self, path: &mut Path) {
|
||||||
|
for segment in &mut path.segments {
|
||||||
|
self.visit_path_arguments_mut(&mut segment.arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) {
|
||||||
|
match arguments {
|
||||||
|
PathArguments::None => {}
|
||||||
|
PathArguments::AngleBracketed(arguments) => {
|
||||||
|
for arg in &mut arguments.args {
|
||||||
|
match arg {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
GenericArgument::Type(arg) => self.visit_type_mut(arg),
|
||||||
|
GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty),
|
||||||
|
GenericArgument::Lifetime(_)
|
||||||
|
| GenericArgument::Const(_)
|
||||||
|
| GenericArgument::AssocConst(_)
|
||||||
|
| GenericArgument::Constraint(_) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PathArguments::Parenthesized(arguments) => {
|
||||||
|
for argument in &mut arguments.inputs {
|
||||||
|
self.visit_type_mut(argument);
|
||||||
|
}
|
||||||
|
self.visit_return_type_mut(&mut arguments.output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) {
|
||||||
|
match return_type {
|
||||||
|
ReturnType::Default => {}
|
||||||
|
ReturnType::Type(_, output) => self.visit_type_mut(output),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
|
||||||
|
match bound {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
|
||||||
|
TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generics_mut(&mut self, generics: &mut Generics) {
|
||||||
|
for param in &mut generics.params {
|
||||||
|
match param {
|
||||||
|
GenericParam::Type(param) => {
|
||||||
|
for bound in &mut param.bounds {
|
||||||
|
self.visit_type_param_bound_mut(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenericParam::Lifetime(_) | GenericParam::Const(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(where_clause) = &mut generics.where_clause {
|
||||||
|
for predicate in &mut where_clause.predicates {
|
||||||
|
match predicate {
|
||||||
|
#![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
|
||||||
|
WherePredicate::Type(predicate) => {
|
||||||
|
self.visit_type_mut(&mut predicate.bounded_ty);
|
||||||
|
for bound in &mut predicate.bounds {
|
||||||
|
self.visit_type_param_bound_mut(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WherePredicate::Lifetime(_) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_data_mut(&mut self, data: &mut Data) {
|
||||||
|
match data {
|
||||||
|
Data::Struct(data) => {
|
||||||
|
for field in &mut data.fields {
|
||||||
|
self.visit_type_mut(&mut field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Data::Enum(data) => {
|
||||||
|
for variant in &mut data.variants {
|
||||||
|
for field in &mut variant.fields {
|
||||||
|
self.visit_type_mut(&mut field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Data::Union(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expr_mut(&mut self, expr: &mut Expr) {
|
||||||
|
match expr {
|
||||||
|
Expr::Binary(expr) => {
|
||||||
|
self.visit_expr_mut(&mut expr.left);
|
||||||
|
self.visit_expr_mut(&mut expr.right);
|
||||||
|
}
|
||||||
|
Expr::Call(expr) => {
|
||||||
|
self.visit_expr_mut(&mut expr.func);
|
||||||
|
for arg in &mut expr.args {
|
||||||
|
self.visit_expr_mut(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Cast(expr) => {
|
||||||
|
self.visit_expr_mut(&mut expr.expr);
|
||||||
|
self.visit_type_mut(&mut expr.ty);
|
||||||
|
}
|
||||||
|
Expr::Field(expr) => self.visit_expr_mut(&mut expr.base),
|
||||||
|
Expr::Index(expr) => {
|
||||||
|
self.visit_expr_mut(&mut expr.expr);
|
||||||
|
self.visit_expr_mut(&mut expr.index);
|
||||||
|
}
|
||||||
|
Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr),
|
||||||
|
Expr::Path(expr) => self.visit_expr_path_mut(expr),
|
||||||
|
Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||||
|
|
||||||
|
pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream {
|
||||||
|
stream
|
||||||
|
.into_iter()
|
||||||
|
.map(|token| respan_token(token, span))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
|
||||||
|
if let TokenTree::Group(g) = &mut token {
|
||||||
|
*g = Group::new(g.delimiter(), respan(g.stream(), span));
|
||||||
|
}
|
||||||
|
token.set_span(span);
|
||||||
|
token
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
use std::fmt::{self, Display};
|
||||||
|
use syn::{Ident, Path};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Symbol(&'static str);
|
||||||
|
|
||||||
|
pub const ALIAS: Symbol = Symbol("alias");
|
||||||
|
pub const BORROW: Symbol = Symbol("borrow");
|
||||||
|
pub const BOUND: Symbol = Symbol("bound");
|
||||||
|
pub const CONTENT: Symbol = Symbol("content");
|
||||||
|
pub const CRATE: Symbol = Symbol("crate");
|
||||||
|
pub const DEFAULT: Symbol = Symbol("default");
|
||||||
|
pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields");
|
||||||
|
pub const DESERIALIZE: Symbol = Symbol("deserialize");
|
||||||
|
pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with");
|
||||||
|
pub const EXPECTING: Symbol = Symbol("expecting");
|
||||||
|
pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier");
|
||||||
|
pub const FLATTEN: Symbol = Symbol("flatten");
|
||||||
|
pub const FROM: Symbol = Symbol("from");
|
||||||
|
pub const GETTER: Symbol = Symbol("getter");
|
||||||
|
pub const INTO: Symbol = Symbol("into");
|
||||||
|
pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive");
|
||||||
|
pub const OTHER: Symbol = Symbol("other");
|
||||||
|
pub const REMOTE: Symbol = Symbol("remote");
|
||||||
|
pub const RENAME: Symbol = Symbol("rename");
|
||||||
|
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 SERDE: Symbol = Symbol("serde");
|
||||||
|
pub const SERIALIZE: Symbol = Symbol("serialize");
|
||||||
|
pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with");
|
||||||
|
pub const SKIP: Symbol = Symbol("skip");
|
||||||
|
pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing");
|
||||||
|
pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing");
|
||||||
|
pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if");
|
||||||
|
pub const TAG: Symbol = Symbol("tag");
|
||||||
|
pub const TRANSPARENT: Symbol = Symbol("transparent");
|
||||||
|
pub const TRY_FROM: Symbol = Symbol("try_from");
|
||||||
|
pub const UNTAGGED: Symbol = Symbol("untagged");
|
||||||
|
pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier");
|
||||||
|
pub const WITH: Symbol = Symbol("with");
|
||||||
|
|
||||||
|
impl PartialEq<Symbol> for Ident {
|
||||||
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
|
self == word.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<Symbol> for &'a Ident {
|
||||||
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
|
*self == word.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<Symbol> for Path {
|
||||||
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
|
self.is_ident(word.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PartialEq<Symbol> for &'a Path {
|
||||||
|
fn eq(&self, word: &Symbol) -> bool {
|
||||||
|
self.is_ident(word.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Symbol {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
+58
-51
@@ -1,8 +1,7 @@
|
|||||||
//! This crate provides Serde's two derive macros.
|
//! This crate provides Serde's two derive macros.
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```edition2021
|
||||||
//! # #[macro_use]
|
//! # use serde_derive::{Deserialize, Serialize};
|
||||||
//! # extern crate serde_derive;
|
|
||||||
//! #
|
//! #
|
||||||
//! #[derive(Serialize, Deserialize)]
|
//! #[derive(Serialize, Deserialize)]
|
||||||
//! # struct S;
|
//! # struct S;
|
||||||
@@ -14,53 +13,65 @@
|
|||||||
//!
|
//!
|
||||||
//! [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.81")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.209")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
// Ignored clippy lints
|
||||||
// Whitelisted clippy lints
|
#![allow(
|
||||||
#![cfg_attr(
|
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
||||||
feature = "cargo-clippy",
|
clippy::branches_sharing_code,
|
||||||
allow(
|
clippy::cognitive_complexity,
|
||||||
cyclomatic_complexity,
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
|
||||||
enum_variant_names,
|
clippy::collapsible_match,
|
||||||
needless_pass_by_value,
|
clippy::derive_partial_eq_without_eq,
|
||||||
redundant_field_names,
|
clippy::enum_variant_names,
|
||||||
too_many_arguments,
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||||
used_underscore_binding,
|
clippy::manual_map,
|
||||||
)
|
clippy::match_like_matches_macro,
|
||||||
|
clippy::needless_pass_by_value,
|
||||||
|
clippy::too_many_arguments,
|
||||||
|
clippy::trivially_copy_pass_by_ref,
|
||||||
|
clippy::used_underscore_binding,
|
||||||
|
clippy::wildcard_in_or_patterns,
|
||||||
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||||
|
clippy::unnested_or_patterns,
|
||||||
)]
|
)]
|
||||||
// Whitelisted clippy_pedantic lints
|
// Ignored clippy_pedantic lints
|
||||||
#![cfg_attr(
|
#![allow(
|
||||||
feature = "cargo-clippy",
|
clippy::cast_possible_truncation,
|
||||||
allow(
|
clippy::checked_conversions,
|
||||||
cast_possible_truncation,
|
clippy::doc_markdown,
|
||||||
doc_markdown,
|
clippy::enum_glob_use,
|
||||||
enum_glob_use,
|
clippy::indexing_slicing,
|
||||||
filter_map,
|
clippy::items_after_statements,
|
||||||
indexing_slicing,
|
clippy::let_underscore_untyped,
|
||||||
items_after_statements,
|
clippy::manual_assert,
|
||||||
match_same_arms,
|
clippy::map_err_ignore,
|
||||||
similar_names,
|
clippy::match_same_arms,
|
||||||
single_match_else,
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
|
||||||
stutter,
|
clippy::match_wildcard_for_single_variants,
|
||||||
unseparated_literal_suffix,
|
clippy::module_name_repetitions,
|
||||||
use_self,
|
clippy::must_use_candidate,
|
||||||
)
|
clippy::similar_names,
|
||||||
|
clippy::single_match_else,
|
||||||
|
clippy::struct_excessive_bools,
|
||||||
|
clippy::too_many_lines,
|
||||||
|
clippy::unseparated_literal_suffix,
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::use_self,
|
||||||
|
clippy::wildcard_imports
|
||||||
)]
|
)]
|
||||||
// The `quote!` macro requires deep recursion.
|
#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
|
||||||
#![recursion_limit = "512"]
|
|
||||||
|
|
||||||
#[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 syn::parse_macro_input;
|
||||||
use syn::DeriveInput;
|
use syn::DeriveInput;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -69,27 +80,23 @@ mod bound;
|
|||||||
mod fragment;
|
mod fragment;
|
||||||
|
|
||||||
mod de;
|
mod de;
|
||||||
|
mod dummy;
|
||||||
mod pretend;
|
mod pretend;
|
||||||
mod ser;
|
mod ser;
|
||||||
mod try;
|
mod this;
|
||||||
|
|
||||||
#[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 {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let mut input = parse_macro_input!(input as DeriveInput);
|
||||||
ser::expand_derive_serialize(&input)
|
ser::expand_derive_serialize(&mut input)
|
||||||
.unwrap_or_else(to_compile_errors)
|
.unwrap_or_else(syn::Error::into_compile_error)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Deserialize, attributes(serde))]
|
#[proc_macro_derive(Deserialize, attributes(serde))]
|
||||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let mut input = parse_macro_input!(input as DeriveInput);
|
||||||
de::expand_derive_deserialize(&input)
|
de::expand_derive_deserialize(&mut input)
|
||||||
.unwrap_or_else(to_compile_errors)
|
.unwrap_or_else(syn::Error::into_compile_error)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
|
|
||||||
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
|
|
||||||
quote!(#(#compile_errors)*)
|
|
||||||
}
|
|
||||||
|
|||||||
+93
-48
@@ -1,7 +1,6 @@
|
|||||||
use proc_macro2::{Span, TokenStream};
|
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
use syn::Ident;
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
use internals::ast::{Container, Data, Field, Style};
|
|
||||||
|
|
||||||
// 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
|
||||||
@@ -20,8 +19,8 @@ use internals::ast::{Container, Data, Field, Style};
|
|||||||
// 8 | enum EnumDef { V }
|
// 8 | enum EnumDef { V }
|
||||||
// | ^
|
// | ^
|
||||||
//
|
//
|
||||||
pub fn pretend_used(cont: &Container) -> TokenStream {
|
pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||||
let pretend_fields = pretend_fields_used(cont);
|
let pretend_fields = pretend_fields_used(cont, is_packed);
|
||||||
let pretend_variants = pretend_variants_used(cont);
|
let pretend_variants = pretend_variants_used(cont);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@@ -32,51 +31,104 @@ pub fn pretend_used(cont: &Container) -> TokenStream {
|
|||||||
|
|
||||||
// For structs with named fields, expands to:
|
// For structs with named fields, expands to:
|
||||||
//
|
//
|
||||||
|
// match None::<&T> {
|
||||||
|
// Some(T { a: __v0, b: __v1 }) => {}
|
||||||
|
// _ => {}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// For packed structs on sufficiently new rustc, expands to:
|
||||||
|
//
|
||||||
|
// match None::<&T> {
|
||||||
|
// Some(__v @ T { a: _, b: _ }) => {
|
||||||
|
// let _ = addr_of!(__v.a);
|
||||||
|
// let _ = addr_of!(__v.b);
|
||||||
|
// }
|
||||||
|
// _ => {}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// For packed structs on older rustc, we assume Sized and !Drop, and expand to:
|
||||||
|
//
|
||||||
// match None::<T> {
|
// match None::<T> {
|
||||||
// Some(T { a: ref __v0, b: ref __v1 }) => {}
|
// Some(T { a: __v0, b: __v1 }) => {}
|
||||||
// _ => {}
|
// _ => {}
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// For enums, expands to the following but only including struct variants:
|
// For enums, expands to the following but only including struct variants:
|
||||||
//
|
//
|
||||||
// match None::<T> {
|
// match None::<&T> {
|
||||||
// Some(T::A { a: ref __v0 }) => {}
|
// Some(T::A { a: __v0 }) => {}
|
||||||
// Some(T::B { b: ref __v0 }) => {}
|
// Some(T::B { b: __v0 }) => {}
|
||||||
// _ => {}
|
// _ => {}
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The `ref` is important in case the user has written a Drop impl on their
|
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||||
// type. Rust does not allow destructuring a struct or enum that has a Drop
|
match &cont.data {
|
||||||
// impl.
|
Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
|
||||||
fn pretend_fields_used(cont: &Container) -> TokenStream {
|
Data::Struct(Style::Struct | Style::Tuple | Style::Newtype, fields) => {
|
||||||
|
if is_packed {
|
||||||
|
pretend_fields_used_struct_packed(cont, fields)
|
||||||
|
} else {
|
||||||
|
pretend_fields_used_struct(cont, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Data::Struct(Style::Unit, _) => quote!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream {
|
||||||
let type_ident = &cont.ident;
|
let type_ident = &cont.ident;
|
||||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||||
|
|
||||||
let patterns = match cont.data {
|
let members = fields.iter().map(|field| &field.member);
|
||||||
Data::Enum(ref variants) => variants
|
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||||
.iter()
|
|
||||||
.filter_map(|variant| match variant.style {
|
|
||||||
Style::Struct => {
|
|
||||||
let variant_ident = &variant.ident;
|
|
||||||
let pat = struct_pattern(&variant.fields);
|
|
||||||
Some(quote!(#type_ident::#variant_ident #pat))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
Data::Struct(Style::Struct, ref fields) => {
|
|
||||||
let pat = struct_pattern(fields);
|
|
||||||
vec![quote!(#type_ident #pat)]
|
|
||||||
}
|
|
||||||
Data::Struct(_, _) => {
|
|
||||||
return quote!();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
match _serde::export::None::<#type_ident #ty_generics> {
|
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||||
|
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream {
|
||||||
|
let type_ident = &cont.ident;
|
||||||
|
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||||
|
|
||||||
|
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||||
|
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
||||||
|
#(
|
||||||
|
let _ = _serde::__private::ptr::addr_of!(__v.#members);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
|
||||||
|
let type_ident = &cont.ident;
|
||||||
|
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||||
|
|
||||||
|
let patterns = variants
|
||||||
|
.iter()
|
||||||
|
.filter_map(|variant| match variant.style {
|
||||||
|
Style::Struct | Style::Tuple | Style::Newtype => {
|
||||||
|
let variant_ident = &variant.ident;
|
||||||
|
let members = variant.fields.iter().map(|field| &field.member);
|
||||||
|
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||||
|
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
|
||||||
|
}
|
||||||
|
Style::Unit => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||||
#(
|
#(
|
||||||
_serde::export::Some(#patterns) => {}
|
_serde::__private::Some(#patterns) => {}
|
||||||
)*
|
)*
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -93,8 +145,8 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
fn pretend_variants_used(cont: &Container) -> TokenStream {
|
fn pretend_variants_used(cont: &Container) -> TokenStream {
|
||||||
let variants = match cont.data {
|
let variants = match &cont.data {
|
||||||
Data::Enum(ref variants) => variants,
|
Data::Enum(variants) => variants,
|
||||||
Data::Struct(_, _) => {
|
Data::Struct(_, _) => {
|
||||||
return quote!();
|
return quote!();
|
||||||
}
|
}
|
||||||
@@ -107,7 +159,7 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
|
|||||||
let cases = variants.iter().map(|variant| {
|
let cases = variants.iter().map(|variant| {
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
let placeholders = &(0..variant.fields.len())
|
let placeholders = &(0..variant.fields.len())
|
||||||
.map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
|
.map(|i| format_ident!("__v{}", i))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let pat = match variant.style {
|
let pat = match variant.style {
|
||||||
@@ -120,8 +172,8 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
|
|||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
match _serde::export::None {
|
match _serde::__private::None {
|
||||||
_serde::export::Some((#(#placeholders,)*)) => {
|
_serde::__private::Some((#(#placeholders,)*)) => {
|
||||||
let _ = #type_ident::#variant_ident #turbofish #pat;
|
let _ = #type_ident::#variant_ident #turbofish #pat;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -131,10 +183,3 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
|
|||||||
|
|
||||||
quote!(#(#cases)*)
|
quote!(#(#cases)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_pattern(fields: &[Field]) -> TokenStream {
|
|
||||||
let members = fields.iter().map(|field| &field.member);
|
|
||||||
let placeholders =
|
|
||||||
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
|
|
||||||
quote!({ #(#members: ref #placeholders),* })
|
|
||||||
}
|
|
||||||
|
|||||||
+247
-196
@@ -1,41 +1,37 @@
|
|||||||
|
use crate::fragment::{Fragment, Match, Stmts};
|
||||||
|
use crate::internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
|
use crate::internals::{attr, replace_receiver, Ctxt, Derive};
|
||||||
|
use crate::{bound, dummy, pretend, 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;
|
pub fn expand_derive_serialize(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
use fragment::{Fragment, Match, Stmts};
|
replace_receiver(input);
|
||||||
use internals::ast::{Container, Data, Field, Style, Variant};
|
|
||||||
use internals::{attr, Ctxt, Derive};
|
|
||||||
use pretend;
|
|
||||||
use try;
|
|
||||||
|
|
||||||
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
|
|
||||||
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) {
|
||||||
Some(cont) => cont,
|
Some(cont) => cont,
|
||||||
None => return Err(ctxt.check().unwrap_err()),
|
None => return Err(ctxt.check().unwrap_err()),
|
||||||
};
|
};
|
||||||
precondition(&ctxt, &cont);
|
precondition(&ctxt, &cont);
|
||||||
try!(ctxt.check());
|
ctxt.check()?;
|
||||||
|
|
||||||
let ident = &cont.ident;
|
let ident = &cont.ident;
|
||||||
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 suffix = ident.to_string().trim_left_matches("r#").to_owned();
|
|
||||||
let dummy_const = Ident::new(
|
|
||||||
&format!("_IMPL_SERIALIZE_FOR_{}", suffix),
|
|
||||||
Span::call_site(),
|
|
||||||
);
|
|
||||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||||
|
let serde = cont.attrs.serde_path();
|
||||||
|
|
||||||
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);
|
let used = pretend::pretend_used(&cont, params.is_packed);
|
||||||
quote! {
|
quote! {
|
||||||
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::export::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
|
||||||
@@ -45,10 +41,10 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
|
|||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
|
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
||||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::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,
|
||||||
{
|
{
|
||||||
#body
|
#body
|
||||||
}
|
}
|
||||||
@@ -56,19 +52,10 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let try_replacement = try::replacement();
|
Ok(dummy::wrap_in_const(
|
||||||
let generated = quote! {
|
cont.attrs.custom_serde_path(),
|
||||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
impl_block,
|
||||||
const #dummy_const: () = {
|
))
|
||||||
#[allow(unknown_lints)]
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
|
|
||||||
#[allow(rust_2018_idioms)]
|
|
||||||
extern crate serde as _serde;
|
|
||||||
#try_replacement
|
|
||||||
#impl_block
|
|
||||||
};
|
|
||||||
};
|
|
||||||
Ok(generated)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precondition(cx: &Ctxt, cont: &Container) {
|
fn precondition(cx: &Ctxt, cont: &Container) {
|
||||||
@@ -89,15 +76,22 @@ struct Parameters {
|
|||||||
self_var: Ident,
|
self_var: Ident,
|
||||||
|
|
||||||
/// Path to the type the impl is for. Either a single `Ident` for local
|
/// Path to the type the impl is for. Either a single `Ident` for local
|
||||||
/// types or `some::remote::Ident` for remote types. Does not include
|
/// types (does not include generic parameters) or `some::remote::Path` for
|
||||||
/// generic parameters.
|
/// remote types.
|
||||||
this: syn::Path,
|
this_type: syn::Path,
|
||||||
|
|
||||||
|
/// Same as `this_type` but using `::<T>` for generic parameters for use in
|
||||||
|
/// expression position.
|
||||||
|
this_value: syn::Path,
|
||||||
|
|
||||||
/// Generics including any explicit and inferred bounds for the impl.
|
/// Generics including any explicit and inferred bounds for the impl.
|
||||||
generics: syn::Generics,
|
generics: syn::Generics,
|
||||||
|
|
||||||
/// Type has a `serde(remote = "...")` attribute.
|
/// Type has a `serde(remote = "...")` attribute.
|
||||||
is_remote: bool,
|
is_remote: bool,
|
||||||
|
|
||||||
|
/// Type has a repr(packed) attribute.
|
||||||
|
is_packed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parameters {
|
impl Parameters {
|
||||||
@@ -109,25 +103,25 @@ impl Parameters {
|
|||||||
Ident::new("self", Span::call_site())
|
Ident::new("self", Span::call_site())
|
||||||
};
|
};
|
||||||
|
|
||||||
let this = match cont.attrs.remote() {
|
let this_type = this::this_type(cont);
|
||||||
Some(remote) => remote.clone(),
|
let this_value = this::this_value(cont);
|
||||||
None => cont.ident.clone().into(),
|
let is_packed = cont.attrs.is_packed();
|
||||||
};
|
|
||||||
|
|
||||||
let generics = build_generics(cont);
|
let generics = build_generics(cont);
|
||||||
|
|
||||||
Parameters {
|
Parameters {
|
||||||
self_var: self_var,
|
self_var,
|
||||||
this: this,
|
this_type,
|
||||||
generics: generics,
|
this_value,
|
||||||
is_remote: is_remote,
|
generics,
|
||||||
|
is_remote,
|
||||||
|
is_packed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type name to use in error messages and `&'static str` arguments to
|
/// Type name to use in error messages and `&'static str` arguments to
|
||||||
/// various Serializer methods.
|
/// various Serializer methods.
|
||||||
fn type_name(&self) -> String {
|
fn type_name(&self) -> String {
|
||||||
self.this.segments.last().unwrap().value().ident.to_string()
|
self.this_type.segments.last().unwrap().ident.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,15 +169,13 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
|||||||
} else if let Some(type_into) = cont.attrs.type_into() {
|
} else if let Some(type_into) = cont.attrs.type_into() {
|
||||||
serialize_into(params, type_into)
|
serialize_into(params, type_into)
|
||||||
} else {
|
} else {
|
||||||
match cont.data {
|
match &cont.data {
|
||||||
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
|
Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs),
|
||||||
Data::Struct(Style::Struct, ref fields) => {
|
Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs),
|
||||||
serialize_struct(params, fields, &cont.attrs)
|
Data::Struct(Style::Tuple, fields) => {
|
||||||
}
|
|
||||||
Data::Struct(Style::Tuple, ref fields) => {
|
|
||||||
serialize_tuple_struct(params, fields, &cont.attrs)
|
serialize_tuple_struct(params, fields, &cont.attrs)
|
||||||
}
|
}
|
||||||
Data::Struct(Style::Newtype, ref fields) => {
|
Data::Struct(Style::Newtype, fields) => {
|
||||||
serialize_newtype_struct(params, &fields[0], &cont.attrs)
|
serialize_newtype_struct(params, &fields[0], &cont.attrs)
|
||||||
}
|
}
|
||||||
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
|
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
|
||||||
@@ -192,8 +184,8 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
|
fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
|
||||||
let fields = match cont.data {
|
let fields = match &cont.data {
|
||||||
Data::Struct(_, ref fields) => fields,
|
Data::Struct(_, fields) => fields,
|
||||||
Data::Enum(_) => unreachable!(),
|
Data::Enum(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,7 +198,7 @@ fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
|
|||||||
None => {
|
None => {
|
||||||
let span = transparent_field.original.span();
|
let span = transparent_field.original.span();
|
||||||
quote_spanned!(span=> _serde::Serialize::serialize)
|
quote_spanned!(span=> _serde::Serialize::serialize)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
@@ -218,7 +210,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::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)),
|
&_serde::__private::Into::<#type_into>::into(_serde::__private::Clone::clone(#self_var)),
|
||||||
__serializer)
|
__serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +262,7 @@ fn serialize_tuple_struct(
|
|||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
|
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||||
@@ -290,22 +282,44 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream {
|
||||||
|
match cattrs.tag() {
|
||||||
|
attr::TagType::Internal { tag } => {
|
||||||
|
let type_name = cattrs.name().serialize_name();
|
||||||
|
let func = struct_trait.serialize_field(Span::call_site());
|
||||||
|
quote! {
|
||||||
|
#func(&mut __serde_state, #tag, #type_name)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => quote! {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_struct_as_struct(
|
fn serialize_struct_as_struct(
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
@@ -316,12 +330,15 @@ fn serialize_struct_as_struct(
|
|||||||
|
|
||||||
let type_name = cattrs.name().serialize_name();
|
let type_name = cattrs.name().serialize_name();
|
||||||
|
|
||||||
|
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct);
|
||||||
|
let tag_field_exists = !tag_field.is_empty();
|
||||||
|
|
||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||||
|
|
||||||
let len = serialized_fields
|
let len = serialized_fields
|
||||||
.map(|field| match field.attrs.skip_serializing_if() {
|
.map(|field| match field.attrs.skip_serializing_if() {
|
||||||
@@ -331,10 +348,14 @@ fn serialize_struct_as_struct(
|
|||||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
.fold(
|
||||||
|
quote!(#tag_field_exists as usize),
|
||||||
|
|sum, expr| quote!(#sum + #expr),
|
||||||
|
);
|
||||||
|
|
||||||
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
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeStruct::end(__serde_state)
|
_serde::ser::SerializeStruct::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -348,41 +369,30 @@ fn serialize_struct_as_map(
|
|||||||
let serialize_fields =
|
let serialize_fields =
|
||||||
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
|
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
|
||||||
|
|
||||||
|
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap);
|
||||||
|
let tag_field_exists = !tag_field.is_empty();
|
||||||
|
|
||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||||
|
|
||||||
let len = if cattrs.has_flatten() {
|
|
||||||
quote!(_serde::export::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!(0), |sum, expr| quote!(#sum + #expr));
|
|
||||||
quote!(_serde::export::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
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)| {
|
||||||
@@ -390,6 +400,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)*
|
||||||
@@ -403,7 +419,7 @@ fn serialize_variant(
|
|||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let this = ¶ms.this;
|
let this_value = ¶ms.this_value;
|
||||||
let variant_ident = &variant.ident;
|
let variant_ident = &variant.ident;
|
||||||
|
|
||||||
if variant.attrs.skip_serializing() {
|
if variant.attrs.skip_serializing() {
|
||||||
@@ -413,7 +429,7 @@ fn serialize_variant(
|
|||||||
variant_ident
|
variant_ident
|
||||||
);
|
);
|
||||||
let skipped_err = quote! {
|
let skipped_err = quote! {
|
||||||
_serde::export::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!(),
|
||||||
@@ -421,48 +437,56 @@ fn serialize_variant(
|
|||||||
Style::Struct => quote!({ .. }),
|
Style::Struct => quote!({ .. }),
|
||||||
};
|
};
|
||||||
quote! {
|
quote! {
|
||||||
#this::#variant_ident #fields_pat => #skipped_err,
|
#this_value::#variant_ident #fields_pat => #skipped_err,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// variant wasn't skipped
|
// variant wasn't skipped
|
||||||
let case = match variant.style {
|
let case = match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote! {
|
quote! {
|
||||||
#this::#variant_ident
|
#this_value::#variant_ident
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Newtype => {
|
Style::Newtype => {
|
||||||
quote! {
|
quote! {
|
||||||
#this::#variant_ident(ref __field0)
|
#this_value::#variant_ident(ref __field0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
let field_names = (0..variant.fields.len())
|
let field_names = (0..variant.fields.len())
|
||||||
.map(|i| Ident::new(&format!("__field{}", i), Span::call_site()));
|
.map(|i| Ident::new(&format!("__field{}", i), Span::call_site()));
|
||||||
quote! {
|
quote! {
|
||||||
#this::#variant_ident(#(ref #field_names),*)
|
#this_value::#variant_ident(#(ref #field_names),*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Struct => {
|
Style::Struct => {
|
||||||
let members = variant.fields.iter().map(|f| &f.member);
|
let members = variant.fields.iter().map(|f| &f.member);
|
||||||
quote! {
|
quote! {
|
||||||
#this::#variant_ident { #(ref #members),* }
|
#this_value::#variant_ident { #(ref #members),* }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = Match(match *cattrs.tag() {
|
let body = Match(match (cattrs.tag(), variant.attrs.untagged()) {
|
||||||
attr::EnumTag::External => {
|
(attr::TagType::External, false) => {
|
||||||
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
|
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Internal { ref tag } => {
|
(attr::TagType::Internal { tag }, false) => {
|
||||||
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Adjacent {
|
(attr::TagType::Adjacent { tag, content }, false) => {
|
||||||
ref tag,
|
serialize_adjacently_tagged_variant(
|
||||||
ref content,
|
params,
|
||||||
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
|
variant,
|
||||||
attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs),
|
cattrs,
|
||||||
|
variant_index,
|
||||||
|
tag,
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(attr::TagType::None, _) | (_, true) => {
|
||||||
|
serialize_untagged_variant(params, variant, cattrs)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@@ -493,7 +517,7 @@ fn serialize_externally_tagged_variant(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
match variant.style {
|
match effective_style(variant) {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
_serde::Serializer::serialize_unit_variant(
|
_serde::Serializer::serialize_unit_variant(
|
||||||
@@ -525,21 +549,21 @@ fn serialize_externally_tagged_variant(
|
|||||||
}
|
}
|
||||||
Style::Tuple => serialize_tuple_variant(
|
Style::Tuple => serialize_tuple_variant(
|
||||||
TupleVariant::ExternallyTagged {
|
TupleVariant::ExternallyTagged {
|
||||||
type_name: type_name,
|
type_name,
|
||||||
variant_index: variant_index,
|
variant_index,
|
||||||
variant_name: variant_name,
|
variant_name,
|
||||||
},
|
},
|
||||||
params,
|
params,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
),
|
),
|
||||||
Style::Struct => serialize_struct_variant(
|
Style::Struct => serialize_struct_variant(
|
||||||
StructVariant::ExternallyTagged {
|
StructVariant::ExternallyTagged {
|
||||||
variant_index: variant_index,
|
variant_index,
|
||||||
variant_name: variant_name,
|
variant_name,
|
||||||
},
|
},
|
||||||
params,
|
params,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
&type_name,
|
type_name,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,7 +583,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,
|
||||||
@@ -570,13 +594,13 @@ fn serialize_internally_tagged_variant(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
match variant.style {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,7 +612,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,
|
||||||
@@ -601,13 +625,10 @@ fn serialize_internally_tagged_variant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Struct => serialize_struct_variant(
|
Style::Struct => serialize_struct_variant(
|
||||||
StructVariant::InternallyTagged {
|
StructVariant::InternallyTagged { tag, variant_name },
|
||||||
tag: tag,
|
|
||||||
variant_name: 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"),
|
||||||
}
|
}
|
||||||
@@ -617,12 +638,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 = ¶ms.this;
|
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);
|
||||||
@@ -630,13 +659,13 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
_serde::Serialize::serialize(#ser, __serializer)
|
_serde::Serialize::serialize(#ser, __serializer)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match variant.style {
|
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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -650,12 +679,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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -666,13 +695,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![]
|
||||||
@@ -697,30 +726,33 @@ fn serialize_adjacently_tagged_variant(
|
|||||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
|
#[doc(hidden)]
|
||||||
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
||||||
data: (#(&'__a #fields_ty,)*),
|
data: (#(&'__a #fields_ty,)*),
|
||||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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::export::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,
|
||||||
{
|
{
|
||||||
|
// Elements that have skip_serializing will be unused.
|
||||||
|
#[allow(unused_variables)]
|
||||||
let (#(#fields_ident,)*) = self.data;
|
let (#(#fields_ident,)*) = self.data;
|
||||||
#inner
|
#inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::export::PhantomData::<#this #ty_generics>,
|
phantom: _serde::__private::PhantomData::<#this_type #ty_generics>,
|
||||||
}));
|
})?;
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,7 +769,7 @@ fn serialize_untagged_variant(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
match variant.style {
|
match effective_style(variant) {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
_serde::Serializer::serialize_unit(__serializer)
|
_serde::Serializer::serialize_unit(__serializer)
|
||||||
@@ -759,16 +791,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 str,
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant_name: String,
|
variant_name: &'a str,
|
||||||
},
|
},
|
||||||
Untagged,
|
Untagged,
|
||||||
}
|
}
|
||||||
@@ -788,7 +820,7 @@ fn serialize_tuple_variant(
|
|||||||
let mut serialized_fields = fields
|
let mut serialized_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
|
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||||
@@ -810,21 +842,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)
|
||||||
}
|
}
|
||||||
@@ -835,17 +867,17 @@ fn serialize_tuple_variant(
|
|||||||
enum StructVariant<'a> {
|
enum StructVariant<'a> {
|
||||||
ExternallyTagged {
|
ExternallyTagged {
|
||||||
variant_index: u32,
|
variant_index: u32,
|
||||||
variant_name: String,
|
variant_name: &'a str,
|
||||||
},
|
},
|
||||||
InternallyTagged {
|
InternallyTagged {
|
||||||
tag: &'a str,
|
tag: &'a str,
|
||||||
variant_name: String,
|
variant_name: &'a str,
|
||||||
},
|
},
|
||||||
Untagged,
|
Untagged,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct_variant<'a>(
|
fn serialize_struct_variant(
|
||||||
context: StructVariant<'a>,
|
context: StructVariant,
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -855,9 +887,9 @@ fn serialize_struct_variant<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let struct_trait = match context {
|
let struct_trait = match context {
|
||||||
StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant),
|
StructVariant::ExternallyTagged { .. } => StructTrait::SerializeStructVariant,
|
||||||
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => {
|
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => {
|
||||||
(StructTrait::SerializeStruct)
|
StructTrait::SerializeStruct
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -887,40 +919,40 @@ fn serialize_struct_variant<'a>(
|
|||||||
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)
|
||||||
}
|
}
|
||||||
@@ -928,8 +960,8 @@ fn serialize_struct_variant<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct_variant_with_flatten<'a>(
|
fn serialize_struct_variant_with_flatten(
|
||||||
context: StructVariant<'a>,
|
context: StructVariant,
|
||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -949,7 +981,7 @@ fn serialize_struct_variant_with_flatten<'a>(
|
|||||||
variant_index,
|
variant_index,
|
||||||
variant_name,
|
variant_name,
|
||||||
} => {
|
} => {
|
||||||
let this = ¶ms.this;
|
let this_type = ¶ms.this_type;
|
||||||
let fields_ty = fields.iter().map(|f| &f.ty);
|
let fields_ty = fields.iter().map(|f| &f.ty);
|
||||||
let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
|
let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -958,20 +990,21 @@ fn serialize_struct_variant_with_flatten<'a>(
|
|||||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
|
#[doc(hidden)]
|
||||||
struct __EnumFlatten #wrapper_generics #where_clause {
|
struct __EnumFlatten #wrapper_generics #where_clause {
|
||||||
data: (#(&'__a #fields_ty,)*),
|
data: (#(&'__a #fields_ty,)*),
|
||||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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::export::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::export::None));
|
_serde::__private::None)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -984,29 +1017,29 @@ fn serialize_struct_variant_with_flatten<'a>(
|
|||||||
#variant_name,
|
#variant_name,
|
||||||
&__EnumFlatten {
|
&__EnumFlatten {
|
||||||
data: (#(#members,)*),
|
data: (#(#members,)*),
|
||||||
phantom: _serde::export::PhantomData::<#this #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::export::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::export::None));
|
_serde::__private::None)?;
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1056,7 @@ fn serialize_tuple_struct_visitor(
|
|||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|&(_, ref field)| !field.attrs.skip_serializing())
|
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||||
.map(|(i, field)| {
|
.map(|(i, field)| {
|
||||||
let mut field_expr = if is_enum {
|
let mut field_expr = if is_enum {
|
||||||
let id = Ident::new(&format!("__field{}", i), Span::call_site());
|
let id = Ident::new(&format!("__field{}", i), Span::call_site());
|
||||||
@@ -1051,7 +1084,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 {
|
||||||
@@ -1077,7 +1110,7 @@ fn serialize_struct_visitor(
|
|||||||
let mut field_expr = if is_enum {
|
let mut field_expr = if is_enum {
|
||||||
quote!(#member)
|
quote!(#member)
|
||||||
} else {
|
} else {
|
||||||
get_member(params, field, &member)
|
get_member(params, field, member)
|
||||||
};
|
};
|
||||||
|
|
||||||
let key_expr = field.attrs.name().serialize_name();
|
let key_expr = field.attrs.name().serialize_name();
|
||||||
@@ -1095,12 +1128,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)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1112,7 +1145,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 {
|
||||||
@@ -1147,9 +1180,9 @@ fn wrap_serialize_variant_with(
|
|||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
let id = match field.member {
|
let id = match &field.member {
|
||||||
Member::Named(ref ident) => ident.clone(),
|
Member::Named(ident) => ident.clone(),
|
||||||
Member::Unnamed(ref member) => {
|
Member::Unnamed(member) => {
|
||||||
Ident::new(&format!("__field{}", member.index), Span::call_site())
|
Ident::new(&format!("__field{}", member.index), Span::call_site())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1170,7 +1203,7 @@ fn wrap_serialize_with(
|
|||||||
field_tys: &[&syn::Type],
|
field_tys: &[&syn::Type],
|
||||||
field_exprs: &[TokenStream],
|
field_exprs: &[TokenStream],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let this = ¶ms.this;
|
let this_type = ¶ms.this_type;
|
||||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||||
|
|
||||||
let wrapper_generics = if field_exprs.is_empty() {
|
let wrapper_generics = if field_exprs.is_empty() {
|
||||||
@@ -1188,13 +1221,14 @@ fn wrap_serialize_with(
|
|||||||
});
|
});
|
||||||
|
|
||||||
quote!({
|
quote!({
|
||||||
|
#[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::export::PhantomData<#this #ty_generics>,
|
phantom: _serde::__private::PhantomData<#this_type #ty_generics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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::export::Result<__S::Ok, __S::Error>
|
fn serialize<__S>(&self, __s: __S) -> _serde::__private::Result<__S::Ok, __S::Error>
|
||||||
where
|
where
|
||||||
__S: _serde::Serializer,
|
__S: _serde::Serializer,
|
||||||
{
|
{
|
||||||
@@ -1204,14 +1238,14 @@ fn wrap_serialize_with(
|
|||||||
|
|
||||||
&__SerializeWith {
|
&__SerializeWith {
|
||||||
values: (#(#field_exprs, )*),
|
values: (#(#field_exprs, )*),
|
||||||
phantom: _serde::export::PhantomData::<#this #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.
|
||||||
@@ -1226,15 +1260,25 @@ fn mut_if(is_mut: bool) -> Option<TokenStream> {
|
|||||||
fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream {
|
fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream {
|
||||||
let self_var = ¶ms.self_var;
|
let self_var = ¶ms.self_var;
|
||||||
match (params.is_remote, field.attrs.getter()) {
|
match (params.is_remote, field.attrs.getter()) {
|
||||||
(false, None) => quote!(&#self_var.#member),
|
(false, None) => {
|
||||||
|
if params.is_packed {
|
||||||
|
quote!(&{#self_var.#member})
|
||||||
|
} else {
|
||||||
|
quote!(&#self_var.#member)
|
||||||
|
}
|
||||||
|
}
|
||||||
(true, None) => {
|
(true, None) => {
|
||||||
let inner = quote!(&#self_var.#member);
|
let inner = if params.is_packed {
|
||||||
|
quote!(&{#self_var.#member})
|
||||||
|
} else {
|
||||||
|
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");
|
||||||
@@ -1242,6 +1286,13 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStrea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn effective_style(variant: &Variant) -> Style {
|
||||||
|
match variant.style {
|
||||||
|
Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit,
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum StructTrait {
|
enum StructTrait {
|
||||||
SerializeMap,
|
SerializeMap,
|
||||||
SerializeStruct,
|
SerializeStruct,
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
use crate::internals::ast::Container;
|
||||||
|
use syn::{Path, PathArguments, Token};
|
||||||
|
|
||||||
|
pub fn this_type(cont: &Container) -> Path {
|
||||||
|
if let Some(remote) = cont.attrs.remote() {
|
||||||
|
let mut this = remote.clone();
|
||||||
|
for segment in &mut this.segments {
|
||||||
|
if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments {
|
||||||
|
arguments.colon2_token = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
Path::from(cont.ident.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn this_value(cont: &Container) -> Path {
|
||||||
|
if let Some(remote) = cont.attrs.remote() {
|
||||||
|
let mut this = remote.clone();
|
||||||
|
for segment in &mut this.segments {
|
||||||
|
if let PathArguments::AngleBracketed(arguments) = &mut segment.arguments {
|
||||||
|
if arguments.colon2_token.is_none() {
|
||||||
|
arguments.colon2_token = Some(Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
Path::from(cont.ident.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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::export::Ok(__val) => __val,
|
|
||||||
_serde::export::Err(__err) => {
|
|
||||||
return _serde::export::Err(__err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,25 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive_internals"
|
name = "serde_derive_internals"
|
||||||
version = "0.24.1" # 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>"]
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
description = "AST representation used by Serde derive macros. Unstable."
|
description = "AST representation used by Serde derive macros. Unstable."
|
||||||
homepage = "https://serde.rs"
|
|
||||||
repository = "https://github.com/serde-rs/serde"
|
|
||||||
documentation = "https://docs.rs/serde_derive_internals"
|
documentation = "https://docs.rs/serde_derive_internals"
|
||||||
|
edition = "2015"
|
||||||
|
exclude = ["build.rs"]
|
||||||
|
homepage = "https://serde.rs"
|
||||||
keywords = ["serde", "serialization"]
|
keywords = ["serde", "serialization"]
|
||||||
include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/serde-rs/serde"
|
||||||
|
rust-version = "1.56"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "0.4"
|
proc-macro2 = { workspace = true }
|
||||||
syn = { version = "0.15", default-features = false, features = ["derive", "parsing", "clone-impls"] }
|
quote = { workspace = true }
|
||||||
|
syn = { workspace = true, features = ["clone-impls", "derive", "parsing", "printing"] }
|
||||||
|
|
||||||
[badges]
|
[package.metadata.docs.rs]
|
||||||
travis-ci = { repository = "serde-rs/serde" }
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
appveyor = { repository = "serde-rs/serde" }
|
rustdoc-args = ["--generate-link-to-definition"]
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Warning: build.rs is not published to crates.io.
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=src/mod.rs");
|
||||||
|
|
||||||
|
println!("cargo:rustc-cfg=check_cfg");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(check_cfg)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(exhaustive)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(serde_build_from_git)");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg(feature, values(\"deserialize_in_place\"))");
|
||||||
|
|
||||||
|
// Sometimes on Windows the git checkout does not correctly wire up the
|
||||||
|
// symlink from serde_derive_internals/src to serde_derive/src/internals.
|
||||||
|
// When this happens we'll just build based on relative paths within the git
|
||||||
|
// repo.
|
||||||
|
let mod_behind_symlink = Path::new("src/mod.rs");
|
||||||
|
if !mod_behind_symlink.exists() {
|
||||||
|
println!("cargo:rustc-cfg=serde_build_from_git");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,50 @@
|
|||||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.24.1")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.29.1")]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
#![cfg_attr(
|
// Ignored clippy lints
|
||||||
feature = "cargo-clippy",
|
#![allow(
|
||||||
allow(
|
clippy::cognitive_complexity,
|
||||||
cyclomatic_complexity,
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
|
||||||
doc_markdown,
|
clippy::collapsible_match,
|
||||||
match_same_arms,
|
clippy::derive_partial_eq_without_eq,
|
||||||
redundant_field_names
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||||
)
|
clippy::manual_map,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
clippy::redundant_field_names,
|
||||||
|
clippy::result_unit_err,
|
||||||
|
clippy::should_implement_trait,
|
||||||
|
clippy::trivially_copy_pass_by_ref,
|
||||||
|
clippy::wildcard_in_or_patterns,
|
||||||
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||||
|
clippy::unnested_or_patterns,
|
||||||
|
)]
|
||||||
|
// Ignored clippy_pedantic lints
|
||||||
|
#![allow(
|
||||||
|
clippy::doc_markdown,
|
||||||
|
clippy::enum_glob_use,
|
||||||
|
clippy::items_after_statements,
|
||||||
|
clippy::let_underscore_untyped,
|
||||||
|
clippy::manual_assert,
|
||||||
|
clippy::match_same_arms,
|
||||||
|
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
|
||||||
|
clippy::match_wildcard_for_single_variants,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::must_use_candidate,
|
||||||
|
clippy::return_self_not_must_use,
|
||||||
|
clippy::similar_names,
|
||||||
|
clippy::single_match_else,
|
||||||
|
clippy::struct_excessive_bools,
|
||||||
|
clippy::too_many_lines,
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::wildcard_imports
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use]
|
extern crate proc_macro2;
|
||||||
|
extern crate quote;
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
|
|
||||||
extern crate proc_macro2;
|
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
|
||||||
|
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
|
||||||
#[path = "src/mod.rs"]
|
|
||||||
mod internals;
|
mod internals;
|
||||||
|
|
||||||
pub use internals::*;
|
pub use internals::*;
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "serde_test"
|
|
||||||
version = "1.0.81" # remember to update html_root_url
|
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
description = "Token De/Serializer for testing De/Serialize implementations"
|
|
||||||
homepage = "https://serde.rs"
|
|
||||||
repository = "https://github.com/serde-rs/serde"
|
|
||||||
documentation = "https://docs.serde.rs/serde_test/"
|
|
||||||
keywords = ["serde", "serialization"]
|
|
||||||
readme = "crates-io.md"
|
|
||||||
include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde = { version = "1.0.60", path = "../serde" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
serde = { version = "1.0", path = "../serde", features = ["rc"] }
|
|
||||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
|
||||||
|
|
||||||
[badges]
|
|
||||||
travis-ci = { repository = "serde-rs/serde" }
|
|
||||||
appveyor = { repository = "serde-rs/serde" }
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../LICENSE-APACHE
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../LICENSE-MIT
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../README.md
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../crates-io.md
|
|
||||||
@@ -1,250 +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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # use serde_test::{assert_ser_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[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,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn assert_ser_tokens<T>(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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// use std::sync::{Arc, Mutex};
|
|
||||||
/// use std::thread;
|
|
||||||
///
|
|
||||||
/// use serde_test::{assert_ser_tokens_error, Token};
|
|
||||||
///
|
|
||||||
/// #[derive(Serialize)]
|
|
||||||
/// struct Example {
|
|
||||||
/// lock: Arc<Mutex<u32>>,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// 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);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn assert_ser_tokens_error<T>(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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # use serde_test::{assert_de_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[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,
|
|
||||||
/// ]);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # use serde_test::{assert_de_tokens_error, Token};
|
|
||||||
/// #
|
|
||||||
/// # fn main() {
|
|
||||||
/// #[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`",
|
|
||||||
/// );
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
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,839 +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.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// extern crate serde;
|
|
||||||
/// extern crate serde_test;
|
|
||||||
///
|
|
||||||
/// 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 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,657 +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],
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! assert_next_token {
|
|
||||||
($de:expr, $expected:expr) => {
|
|
||||||
match $de.next_token_opt() {
|
|
||||||
Some(token) if token == $expected => {}
|
|
||||||
Some(other) => panic!(
|
|
||||||
"expected Token::{} but deserialization wants Token::{}",
|
|
||||||
other, $expected
|
|
||||||
),
|
|
||||||
None => panic!(
|
|
||||||
"end of tokens but deserialization wants Token::{}",
|
|
||||||
$expected
|
|
||||||
),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! unexpected {
|
|
||||||
($token:expr) => {
|
|
||||||
panic!("deserialization did not expect this token: {}", $token)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! end_of_tokens {
|
|
||||||
() => {
|
|
||||||
panic!("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) -> Token {
|
|
||||||
match self.peek_token_opt() {
|
|
||||||
Some(token) => token,
|
|
||||||
None => 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) -> Token {
|
|
||||||
match self.tokens.split_first() {
|
|
||||||
Some((&first, rest)) => {
|
|
||||||
self.tokens = rest;
|
|
||||||
first
|
|
||||||
}
|
|
||||||
None => end_of_tokens!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = try!(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 = try!(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::Bytes(variant), Token::Unit) => {
|
|
||||||
self.next_token();
|
|
||||||
visitor.visit_bytes(variant)
|
|
||||||
}
|
|
||||||
(Token::U32(variant), Token::Unit) => {
|
|
||||||
self.next_token();
|
|
||||||
visitor.visit_u32(variant)
|
|
||||||
}
|
|
||||||
(variant, Token::Unit) => 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 => {
|
|
||||||
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 })
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unexpected!(self.next_token());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = try!(seed.deserialize(de));
|
|
||||||
Ok((value, self))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let value = try!(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 {
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
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) => 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,
|
|
||||||
};
|
|
||||||
try!(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,
|
|
||||||
};
|
|
||||||
try!(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,195 +0,0 @@
|
|||||||
//! This crate provides a convenient concise way to write unit tests for
|
|
||||||
//! implementations of [`Serialize`] and [`Deserialize`].
|
|
||||||
//!
|
|
||||||
//! [`Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
|
||||||
//! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
|
||||||
//!
|
|
||||||
//! 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`]: https://docs.serde.rs/serde/ser/trait.Serializer.html
|
|
||||||
//! [`Token`]: https://docs.serde.rs/serde_test/enum.Token.html
|
|
||||||
//! [`assert_ser_tokens`]: https://docs.serde.rs/serde_test/fn.assert_ser_tokens.html
|
|
||||||
//! [`assert_de_tokens`]: https://docs.serde.rs/serde_test/fn.assert_de_tokens.html
|
|
||||||
//! [`assert_tokens`]: https://docs.serde.rs/serde_test/fn.assert_tokens.html
|
|
||||||
//!
|
|
||||||
//! Here is an example from the [`linked-hash-map`] crate.
|
|
||||||
//!
|
|
||||||
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! # extern crate serde;
|
|
||||||
//! #
|
|
||||||
//! # macro_rules! ignore {
|
|
||||||
//! # ($($tt:tt)+) => {}
|
|
||||||
//! # }
|
|
||||||
//! #
|
|
||||||
//! # ignore! {
|
|
||||||
//! extern crate linked_hash_map;
|
|
||||||
//! use linked_hash_map::LinkedHashMap;
|
|
||||||
//! # }
|
|
||||||
//!
|
|
||||||
//! extern crate serde_test;
|
|
||||||
//! 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.81")]
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
|
||||||
// Whitelisted clippy lints
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
|
||||||
// Whitelisted clippy_pedantic lints
|
|
||||||
#![cfg_attr(
|
|
||||||
feature = "cargo-clippy",
|
|
||||||
allow(
|
|
||||||
empty_line_after_outer_attr,
|
|
||||||
missing_docs_in_private_items,
|
|
||||||
redundant_field_names,
|
|
||||||
stutter,
|
|
||||||
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};
|
|
||||||
|
|
||||||
// Not public API.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub use de::Deserializer;
|
|
||||||
@@ -1,464 +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, $expected:ident) => {
|
|
||||||
assert_next_token!($ser, stringify!($expected), Token::$expected, true);
|
|
||||||
};
|
|
||||||
($ser:expr, $expected:ident($v:expr)) => {
|
|
||||||
assert_next_token!(
|
|
||||||
$ser,
|
|
||||||
format_args!(concat!(stringify!($expected), "({:?})"), $v),
|
|
||||||
Token::$expected(v),
|
|
||||||
v == $v
|
|
||||||
);
|
|
||||||
};
|
|
||||||
($ser:expr, $expected: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!($expected), " {{ {}}}"), field_format()),
|
|
||||||
Token::$expected { $($k),* },
|
|
||||||
($($k,)*) == compare
|
|
||||||
);
|
|
||||||
};
|
|
||||||
($ser:expr, $expected:expr, $pat:pat, $guard:expr) => {
|
|
||||||
match $ser.next_token() {
|
|
||||||
Some($pat) if $guard => {}
|
|
||||||
Some(other) => {
|
|
||||||
panic!("expected Token::{} but serialized as {}",
|
|
||||||
$expected, other);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
panic!("expected Token::{} after end of serialized tokens",
|
|
||||||
$expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
{
|
|
||||||
try!(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,
|
|
||||||
{
|
|
||||||
try!(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,564 +0,0 @@
|
|||||||
use std::fmt::{self, Debug, Display};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
||||||
pub enum Token {
|
|
||||||
/// A serialized `bool`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&true, &[Token::Bool(true)]);
|
|
||||||
/// ```
|
|
||||||
Bool(bool),
|
|
||||||
|
|
||||||
/// A serialized `i8`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i8, &[Token::I8(0)]);
|
|
||||||
/// ```
|
|
||||||
I8(i8),
|
|
||||||
|
|
||||||
/// A serialized `i16`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i16, &[Token::I16(0)]);
|
|
||||||
/// ```
|
|
||||||
I16(i16),
|
|
||||||
|
|
||||||
/// A serialized `i32`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i32, &[Token::I32(0)]);
|
|
||||||
/// ```
|
|
||||||
I32(i32),
|
|
||||||
|
|
||||||
/// A serialized `i64`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0i64, &[Token::I64(0)]);
|
|
||||||
/// ```
|
|
||||||
I64(i64),
|
|
||||||
|
|
||||||
/// A serialized `u8`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u8, &[Token::U8(0)]);
|
|
||||||
/// ```
|
|
||||||
U8(u8),
|
|
||||||
|
|
||||||
/// A serialized `u16`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u16, &[Token::U16(0)]);
|
|
||||||
/// ```
|
|
||||||
U16(u16),
|
|
||||||
|
|
||||||
/// A serialized `u32`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u32, &[Token::U32(0)]);
|
|
||||||
/// ```
|
|
||||||
U32(u32),
|
|
||||||
|
|
||||||
/// A serialized `u64`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0u64, &[Token::U64(0)]);
|
|
||||||
/// ```
|
|
||||||
U64(u64),
|
|
||||||
|
|
||||||
/// A serialized `f32`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
|
|
||||||
/// ```
|
|
||||||
F32(f32),
|
|
||||||
|
|
||||||
/// A serialized `f64`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
|
|
||||||
/// ```
|
|
||||||
F64(f64),
|
|
||||||
|
|
||||||
/// A serialized `char`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&'\n', &[Token::Char('\n')]);
|
|
||||||
/// ```
|
|
||||||
Char(char),
|
|
||||||
|
|
||||||
/// A serialized `str`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let s = String::from("transient");
|
|
||||||
/// assert_tokens(&s, &[Token::Str("transient")]);
|
|
||||||
/// ```
|
|
||||||
Str(&'static str),
|
|
||||||
|
|
||||||
/// A borrowed `str`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let s: &str = "borrowed";
|
|
||||||
/// assert_tokens(&s, &[Token::BorrowedStr("borrowed")]);
|
|
||||||
/// ```
|
|
||||||
BorrowedStr(&'static str),
|
|
||||||
|
|
||||||
/// A serialized `String`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// let opt = Some('c');
|
|
||||||
/// assert_tokens(&opt, &[
|
|
||||||
/// Token::Some,
|
|
||||||
/// Token::Char('c'),
|
|
||||||
/// ]);
|
|
||||||
/// ```
|
|
||||||
Some,
|
|
||||||
|
|
||||||
/// A serialized `()`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use serde_test::{assert_tokens, Token};
|
|
||||||
/// #
|
|
||||||
/// assert_tokens(&(), &[Token::Unit]);
|
|
||||||
/// ```
|
|
||||||
Unit,
|
|
||||||
|
|
||||||
/// A serialized unit struct of the given name.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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`.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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.
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # #[macro_use]
|
|
||||||
/// # extern crate serde_derive;
|
|
||||||
/// #
|
|
||||||
/// # extern crate serde;
|
|
||||||
/// # extern crate serde_test;
|
|
||||||
/// #
|
|
||||||
/// # 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+12
-9
@@ -2,17 +2,20 @@
|
|||||||
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"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unstable = ["serde/unstable", "compiletest_rs"]
|
unstable = ["serde/unstable"]
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
fnv = "1.0"
|
|
||||||
rustc-serialize = "0.3.16"
|
|
||||||
serde = { path = "../serde", features = ["rc"] }
|
|
||||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
|
||||||
serde_test = { path = "../serde_test" }
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
compiletest_rs = { version = "0.3", optional = true, features = ["stable"] }
|
serde = { path = "../serde" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
automod = "1.0.1"
|
||||||
|
fnv = "1.0"
|
||||||
|
rustversion = "1.0"
|
||||||
|
serde = { path = "../serde", features = ["rc"] }
|
||||||
|
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||||
|
serde_test = "1.0.176"
|
||||||
|
trybuild = { version = "1.0.97", features = ["diff"] }
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "serde_test_suite_deps"
|
|
||||||
version = "0.0.0"
|
|
||||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
|
||||||
publish = false
|
|
||||||
|
|
||||||
[workspace]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
serde = { path = "../../serde" }
|
|
||||||
serde_derive = { path = "../../serde_derive" }
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#![feature(/*=============================================]
|
|
||||||
#![=== Serde test suite requires a nightly compiler. ===]
|
|
||||||
#![====================================================*/)]
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
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>"]
|
||||||
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
#![allow(internal_features)]
|
||||||
#![feature(lang_items, start)]
|
#![feature(lang_items, start)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
0
|
0
|
||||||
@@ -21,25 +20,24 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[macro_use]
|
use serde_derive::{Deserialize, Serialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
#[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),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ impl<'de> Visitor<'de> for ByteBufVisitor {
|
|||||||
V: SeqAccess<'de>,
|
V: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
while let Some(value) = try!(visitor.next_element()) {
|
while let Some(value) = visitor.next_element()? {
|
||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
Ok(values)
|
Ok(values)
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
#![cfg(feature = "unstable")]
|
#[cfg_attr(target_os = "emscripten", ignore = "disabled on Emscripten")]
|
||||||
|
#[rustversion::attr(not(nightly), ignore = "requires nightly")]
|
||||||
extern crate compiletest_rs as compiletest;
|
#[cfg_attr(miri, ignore = "incompatible with miri")]
|
||||||
|
#[allow(unused_attributes)]
|
||||||
#[test]
|
#[test]
|
||||||
fn ui() {
|
fn ui() {
|
||||||
let config = compiletest::Config {
|
let t = trybuild::TestCases::new();
|
||||||
mode: compiletest::common::Mode::Ui,
|
t.compile_fail("tests/ui/**/*.rs");
|
||||||
src_base: std::path::PathBuf::from("tests/ui"),
|
|
||||||
target_rustcflags: Some("-L deps/target/debug/deps".to_owned()),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
compiletest::run_tests(&config);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +1,79 @@
|
|||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
|
||||||
|
use serde_test::Token;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
macro_rules! btreeset {
|
macro_rules! btreeset {
|
||||||
() => {
|
() => {
|
||||||
BTreeSet::new()
|
BTreeSet::new()
|
||||||
};
|
};
|
||||||
($($value:expr),+) => {
|
($($value:expr),+) => {{
|
||||||
{
|
let mut set = BTreeSet::new();
|
||||||
let mut set = BTreeSet::new();
|
$(set.insert($value);)+
|
||||||
$(set.insert($value);)+
|
set
|
||||||
set
|
}};
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! btreemap {
|
macro_rules! btreemap {
|
||||||
() => {
|
() => {
|
||||||
BTreeMap::new()
|
BTreeMap::new()
|
||||||
};
|
};
|
||||||
($($key:expr => $value:expr),+) => {
|
($($key:expr => $value:expr),+) => {{
|
||||||
{
|
let mut map = BTreeMap::new();
|
||||||
let mut map = BTreeMap::new();
|
$(map.insert($key, $value);)+
|
||||||
$(map.insert($key, $value);)+
|
map
|
||||||
map
|
}};
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! hashset {
|
macro_rules! hashset {
|
||||||
() => {
|
() => {
|
||||||
HashSet::new()
|
HashSet::new()
|
||||||
};
|
};
|
||||||
($($value:expr),+) => {
|
($($value:expr),+) => {{
|
||||||
{
|
let mut set = HashSet::new();
|
||||||
let mut set = HashSet::new();
|
$(set.insert($value);)+
|
||||||
$(set.insert($value);)+
|
set
|
||||||
set
|
}};
|
||||||
}
|
($hasher:ident @ $($value:expr),+) => {{
|
||||||
};
|
use std::hash::BuildHasherDefault;
|
||||||
($hasher:ident @ $($value:expr),+) => {
|
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||||
{
|
$(set.insert($value);)+
|
||||||
use std::hash::BuildHasherDefault;
|
set
|
||||||
let mut set = HashSet::with_hasher(BuildHasherDefault::<$hasher>::default());
|
}};
|
||||||
$(set.insert($value);)+
|
|
||||||
set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! hashmap {
|
macro_rules! hashmap {
|
||||||
() => {
|
() => {
|
||||||
HashMap::new()
|
HashMap::new()
|
||||||
};
|
};
|
||||||
($($key:expr => $value:expr),+) => {
|
($($key:expr => $value:expr),+) => {{
|
||||||
{
|
let mut map = HashMap::new();
|
||||||
let mut map = HashMap::new();
|
$(map.insert($key, $value);)+
|
||||||
$(map.insert($key, $value);)+
|
map
|
||||||
map
|
}};
|
||||||
}
|
($hasher:ident @ $($key:expr => $value:expr),+) => {{
|
||||||
};
|
use std::hash::BuildHasherDefault;
|
||||||
($hasher:ident @ $($key:expr => $value:expr),+) => {
|
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
|
||||||
{
|
$(map.insert($key, $value);)+
|
||||||
use std::hash::BuildHasherDefault;
|
map
|
||||||
let mut map = HashMap::with_hasher(BuildHasherDefault::<$hasher>::default());
|
}};
|
||||||
$(map.insert($key, $value);)+
|
}
|
||||||
map
|
|
||||||
}
|
pub trait SingleTokenIntoIterator {
|
||||||
|
fn into_iter(self) -> iter::Once<Token>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SingleTokenIntoIterator for Token {
|
||||||
|
fn into_iter(self) -> iter::Once<Token> {
|
||||||
|
iter::once(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! seq_impl {
|
|
||||||
(seq $first:expr,) => {
|
|
||||||
seq_impl!(seq $first)
|
|
||||||
};
|
|
||||||
($first:expr,) => {
|
|
||||||
seq_impl!($first)
|
|
||||||
};
|
|
||||||
(seq $first:expr) => {
|
|
||||||
$first.into_iter()
|
|
||||||
};
|
|
||||||
($first:expr) => {
|
|
||||||
Some($first).into_iter()
|
|
||||||
};
|
|
||||||
(seq $first:expr , $( $elem: tt)*) => {
|
|
||||||
$first.into_iter().chain(seq!( $($elem)* ))
|
|
||||||
};
|
|
||||||
($first:expr , $($elem: tt)*) => {
|
|
||||||
Some($first).into_iter().chain(seq!( $($elem)* ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
macro_rules! seq {
|
macro_rules! seq {
|
||||||
($($tt: tt)*) => {
|
($($elem:expr),* $(,)?) => {{
|
||||||
seq_impl!($($tt)*).collect::<Vec<_>>()
|
use crate::macros::SingleTokenIntoIterator;
|
||||||
};
|
let mut vec = Vec::new();
|
||||||
|
$(<Vec<Token> as Extend<Token>>::extend(&mut vec, $elem.into_iter());)*
|
||||||
|
vec
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mod regression {
|
||||||
|
automod::dir!("tests/regression");
|
||||||
|
}
|
||||||
@@ -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),
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Nested;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub enum ExternallyTagged {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
string: &'static str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "tag")]
|
||||||
|
pub enum InternallyTagged {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
string: &'static str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content")]
|
||||||
|
pub enum AdjacentlyTagged {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
string: &'static str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum UntaggedWorkaround {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
nested: Nested,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
string: &'static str,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
macro_rules! bug {
|
||||||
|
($serde_path:literal) => {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(crate = $serde_path)]
|
||||||
|
pub struct Struct;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bug!("serde");
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde()]
|
||||||
|
pub struct S;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
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 {}
|
||||||
+1564
-953
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
|||||||
#[macro_use]
|
#![allow(
|
||||||
extern crate serde_derive;
|
clippy::derive_partial_eq_without_eq,
|
||||||
|
clippy::items_after_statements,
|
||||||
|
clippy::used_underscore_binding
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate serde;
|
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::de::{Deserialize, Deserializer, IntoDeserializer};
|
||||||
|
use serde_derive::Deserialize;
|
||||||
extern crate serde_test;
|
|
||||||
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -96,6 +97,30 @@ fn test_struct() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_field_identifier() {
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(field_identifier)]
|
||||||
|
enum FieldStr<'a> {
|
||||||
|
#[serde(borrow)]
|
||||||
|
Str(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(&FieldStr::Str("value"), &[Token::BorrowedStr("value")]);
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(field_identifier)]
|
||||||
|
enum FieldBytes<'a> {
|
||||||
|
#[serde(borrow)]
|
||||||
|
Bytes(&'a [u8]),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&FieldBytes::Bytes(b"value"),
|
||||||
|
&[Token::BorrowedBytes(b"value")],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cow() {
|
fn test_cow() {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -106,20 +131,22 @@ fn test_cow() {
|
|||||||
borrowed: Cow<'b, str>,
|
borrowed: Cow<'b, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens = &[
|
struct BorrowedStr(&'static str);
|
||||||
Token::Struct {
|
|
||||||
name: "Cows",
|
|
||||||
len: 2,
|
|
||||||
},
|
|
||||||
Token::Str("copied"),
|
|
||||||
Token::BorrowedStr("copied"),
|
|
||||||
Token::Str("borrowed"),
|
|
||||||
Token::BorrowedStr("borrowed"),
|
|
||||||
Token::StructEnd,
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut de = serde_test::Deserializer::new(tokens);
|
impl<'de> IntoDeserializer<'de> for BorrowedStr {
|
||||||
let cows = Cows::deserialize(&mut de).unwrap();
|
type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>;
|
||||||
|
|
||||||
|
fn into_deserializer(self) -> Self::Deserializer {
|
||||||
|
BorrowedStrDeserializer::new(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let de = MapDeserializer::new(IntoIterator::into_iter([
|
||||||
|
("copied", BorrowedStr("copied")),
|
||||||
|
("borrowed", BorrowedStr("borrowed")),
|
||||||
|
]));
|
||||||
|
|
||||||
|
let cows = Cows::deserialize(de).unwrap();
|
||||||
|
|
||||||
match cows.copied {
|
match cows.copied {
|
||||||
Cow::Owned(ref s) if s == "copied" => {}
|
Cow::Owned(ref s) if s == "copied" => {}
|
||||||
@@ -135,7 +162,7 @@ fn test_cow() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_lifetimes() {
|
fn test_lifetimes() {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Cows<'a, 'b> {
|
pub struct Cows<'a, 'b> {
|
||||||
_copied: Cow<'a, str>,
|
_copied: Cow<'a, str>,
|
||||||
|
|
||||||
#[serde(borrow)]
|
#[serde(borrow)]
|
||||||
@@ -151,7 +178,7 @@ fn test_lifetimes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Wrap<'a, 'b> {
|
pub struct Wrap<'a, 'b> {
|
||||||
#[serde(borrow = "'b")]
|
#[serde(borrow = "'b")]
|
||||||
_cows: Cows<'a, 'b>,
|
_cows: Cows<'a, 'b>,
|
||||||
}
|
}
|
||||||
|
|||||||
+1995
-942
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,799 @@
|
|||||||
|
#![deny(trivial_numeric_casts)]
|
||||||
|
#![allow(
|
||||||
|
clippy::derive_partial_eq_without_eq,
|
||||||
|
clippy::enum_variant_names,
|
||||||
|
clippy::redundant_field_names,
|
||||||
|
clippy::too_many_lines
|
||||||
|
)]
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum AdjacentlyTagged<T> {
|
||||||
|
Unit,
|
||||||
|
Newtype(T),
|
||||||
|
Tuple(u8, u8),
|
||||||
|
Struct { f: u8 },
|
||||||
|
}
|
||||||
|
|
||||||
|
mod unit {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_str_tag_only() {
|
||||||
|
// Map: tag only
|
||||||
|
assert_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag only and incorrect hint for number of elements
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_int_tag_only() {
|
||||||
|
// Map: tag (as number) only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::U16(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_bytes_tag_only() {
|
||||||
|
// Map: tag only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag only
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_str_tag_content() {
|
||||||
|
// Map: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: tag + content + excess fields (f, g, h)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("g"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_int_tag_content() {
|
||||||
|
// Map: tag (as number) + content (as number)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U8(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content (as number) + tag (as number)
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U64(1),
|
||||||
|
Token::Unit,
|
||||||
|
Token::U64(0),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_bytes_tag_content() {
|
||||||
|
// Map: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::BorrowedBytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Bytes(b"t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_tag_content() {
|
||||||
|
// Seq: tag and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Unit,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::Str("Unit"), // tag
|
||||||
|
Token::Unit, // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as borrowed string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit::<u8>,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::BorrowedStr("Unit"), // tag
|
||||||
|
Token::Unit, // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod newtype {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_tag_only() {
|
||||||
|
// optional newtype with no content field
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Newtype::<Option<u8>>(None),
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map_tag_content() {
|
||||||
|
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Newtype::<u8>(1);
|
||||||
|
|
||||||
|
// Seq: tag and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::Str("Newtype"), // tag
|
||||||
|
Token::U8(1), // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Seq: tag (as borrowed string) and content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: None },
|
||||||
|
Token::BorrowedStr("Newtype"), // tag
|
||||||
|
Token::U8(1), // content
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_with_newtype() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct NewtypeStruct(u32);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Newtype(NewtypeStruct(5)),
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::NewtypeStruct {
|
||||||
|
name: "NewtypeStruct",
|
||||||
|
},
|
||||||
|
Token::U32(5),
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tuple {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Tuple::<u8>(1, 1);
|
||||||
|
|
||||||
|
// Seq: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Tuple",
|
||||||
|
},
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleEnd,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod struct_ {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn map() {
|
||||||
|
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||||
|
|
||||||
|
// Map: tag + content
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map: content + tag
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq() {
|
||||||
|
let value = AdjacentlyTagged::Struct::<u8> { f: 1 };
|
||||||
|
|
||||||
|
// Seq: tag + content
|
||||||
|
assert_de_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::Seq { len: Some(2) },
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Struct",
|
||||||
|
},
|
||||||
|
Token::Struct {
|
||||||
|
name: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
Token::SeqEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn struct_with_flatten() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum Data {
|
||||||
|
A {
|
||||||
|
a: i32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
flat: Flat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Flat {
|
||||||
|
b: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A {
|
||||||
|
a: 0,
|
||||||
|
flat: Flat { b: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Data",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "Data",
|
||||||
|
variant: "A",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expecting_message() {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content")]
|
||||||
|
#[serde(expecting = "something strange...")]
|
||||||
|
enum Enum {
|
||||||
|
AdjacentlyTagged,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Enum>(
|
||||||
|
&[Token::Str("AdjacentlyTagged")],
|
||||||
|
r#"invalid type: string "AdjacentlyTagged", expected something strange..."#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Enum>(
|
||||||
|
&[Token::Map { len: None }, Token::Unit],
|
||||||
|
r#"invalid type: unit value, expected "tag", "content", or other ignored fields"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||||
|
assert_de_tokens_error::<Enum>(
|
||||||
|
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
|
||||||
|
"invalid type: unit value, expected variant of enum Enum",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partially_untagged() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(tag = "t", content = "c")]
|
||||||
|
enum Data {
|
||||||
|
A(u32),
|
||||||
|
B,
|
||||||
|
#[serde(untagged)]
|
||||||
|
Var(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A(7);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::Str("A"),
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::U32(7),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let data = Data::Var(42);
|
||||||
|
|
||||||
|
assert_de_tokens(&data, &[Token::U32(42)]);
|
||||||
|
|
||||||
|
// TODO test error output
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deny_unknown_fields() {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "t", content = "c", deny_unknown_fields)]
|
||||||
|
enum AdjacentlyTagged {
|
||||||
|
Unit,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&AdjacentlyTagged::Unit,
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Str("c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Str("h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: string "h", expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U64(0), // tag field
|
||||||
|
Token::UnitVariant {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
variant: "Unit",
|
||||||
|
},
|
||||||
|
Token::U64(3),
|
||||||
|
],
|
||||||
|
r#"invalid value: integer `3`, expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<AdjacentlyTagged>(
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "AdjacentlyTagged",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::Bytes(b"c"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::Bytes(b"h"),
|
||||||
|
],
|
||||||
|
r#"invalid value: byte array, expected "t" or "c""#,
|
||||||
|
);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,583 @@
|
|||||||
|
#![deny(trivial_numeric_casts)]
|
||||||
|
#![allow(
|
||||||
|
clippy::derive_partial_eq_without_eq,
|
||||||
|
clippy::enum_variant_names,
|
||||||
|
clippy::redundant_field_names,
|
||||||
|
clippy::too_many_lines
|
||||||
|
)]
|
||||||
|
|
||||||
|
mod bytes;
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Untagged {
|
||||||
|
A { a: u8 },
|
||||||
|
B { b: u8 },
|
||||||
|
C,
|
||||||
|
D(u8),
|
||||||
|
E(String),
|
||||||
|
F(u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::A { a: 1 },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::B { b: 2 },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Serializes to unit, deserializes from either depending on format's
|
||||||
|
// preference.
|
||||||
|
assert_tokens(&Untagged::C, &[Token::Unit]);
|
||||||
|
assert_de_tokens(&Untagged::C, &[Token::None]);
|
||||||
|
|
||||||
|
assert_tokens(&Untagged::D(4), &[Token::U8(4)]);
|
||||||
|
assert_tokens(&Untagged::E("e".to_owned()), &[Token::Str("e")]);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::F(1, 2),
|
||||||
|
&[
|
||||||
|
Token::Tuple { len: 2 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::TupleEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Untagged>(
|
||||||
|
&[Token::Tuple { len: 1 }, Token::U8(1), Token::TupleEnd],
|
||||||
|
"data did not match any variant of untagged enum Untagged",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Untagged>(
|
||||||
|
&[
|
||||||
|
Token::Tuple { len: 3 },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(2),
|
||||||
|
Token::U8(3),
|
||||||
|
Token::TupleEnd,
|
||||||
|
],
|
||||||
|
"data did not match any variant of untagged enum Untagged",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_unit_and_empty_map() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Unit;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Message {
|
||||||
|
Unit(Unit),
|
||||||
|
Map(BTreeMap<String, String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Message::Map(BTreeMap::new()),
|
||||||
|
&[Token::Map { len: Some(0) }, Token::MapEnd],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_newtype_struct
|
||||||
|
#[test]
|
||||||
|
fn newtype_struct() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct NewtypeStruct(u32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum E {
|
||||||
|
Newtype(NewtypeStruct),
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = E::Newtype(NewtypeStruct(5));
|
||||||
|
|
||||||
|
// Content::Newtype case
|
||||||
|
assert_tokens(
|
||||||
|
&value,
|
||||||
|
&[
|
||||||
|
Token::NewtypeStruct {
|
||||||
|
name: "NewtypeStruct",
|
||||||
|
},
|
||||||
|
Token::U32(5),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// _ case
|
||||||
|
assert_de_tokens(&value, &[Token::U32(5)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod newtype_enum {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Outer {
|
||||||
|
Inner(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
enum Inner {
|
||||||
|
Unit,
|
||||||
|
Newtype(u8),
|
||||||
|
Tuple0(),
|
||||||
|
Tuple2(u8, u8),
|
||||||
|
Struct { f: u8 },
|
||||||
|
EmptyStruct {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::unit_variant
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Unit),
|
||||||
|
&[Token::UnitVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Unit",
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::newtype_variant_seed
|
||||||
|
#[test]
|
||||||
|
fn newtype() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Newtype(1)),
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Newtype",
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||||
|
#[test]
|
||||||
|
fn tuple0() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Tuple0()),
|
||||||
|
&[
|
||||||
|
Token::TupleVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Tuple0",
|
||||||
|
len: 0,
|
||||||
|
},
|
||||||
|
Token::TupleVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::tuple_variant
|
||||||
|
#[test]
|
||||||
|
fn tuple2() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Tuple2(1, 1)),
|
||||||
|
&[
|
||||||
|
Token::TupleVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Tuple2",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::U8(1),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::TupleVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Map case
|
||||||
|
#[test]
|
||||||
|
fn struct_from_map() {
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||||
|
&[
|
||||||
|
Token::StructVariant {
|
||||||
|
name: "Inner",
|
||||||
|
variant: "Struct",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("f"),
|
||||||
|
Token::U8(1),
|
||||||
|
Token::StructVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Seq case
|
||||||
|
#[test]
|
||||||
|
fn struct_from_seq() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::Struct { f: 1 }),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("Struct"),
|
||||||
|
// content
|
||||||
|
Token::Seq { len: Some(1) },
|
||||||
|
Token::U8(1),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Map case
|
||||||
|
// Special case - empty map
|
||||||
|
#[test]
|
||||||
|
fn empty_struct_from_map() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::EmptyStruct {}),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("EmptyStruct"),
|
||||||
|
// content
|
||||||
|
Token::Map { len: Some(0) },
|
||||||
|
Token::MapEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::VariantRefDeserializer::struct_variant
|
||||||
|
// Content::Seq case
|
||||||
|
// Special case - empty seq
|
||||||
|
#[test]
|
||||||
|
fn empty_struct_from_seq() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Outer::Inner(Inner::EmptyStruct {}),
|
||||||
|
&[
|
||||||
|
Token::Map { len: Some(1) },
|
||||||
|
// tag
|
||||||
|
Token::Str("EmptyStruct"),
|
||||||
|
// content
|
||||||
|
Token::Seq { len: Some(0) },
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaches crate::private::de::content::ContentRefDeserializer::deserialize_option
|
||||||
|
mod with_optional_field {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Enum {
|
||||||
|
Struct { optional: Option<u32> },
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn some() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Struct { optional: Some(42) },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::Some,
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn some_without_marker() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Enum::Struct { optional: Some(42) },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::U32(42),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn none() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Struct { optional: None },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Enum",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::None,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unit() {
|
||||||
|
assert_de_tokens(
|
||||||
|
&Enum::Struct { optional: None },
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("optional"),
|
||||||
|
Token::Unit,
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_and_bytes() {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Untagged {
|
||||||
|
String {
|
||||||
|
string: String,
|
||||||
|
},
|
||||||
|
Bytes {
|
||||||
|
#[serde(with = "bytes")]
|
||||||
|
bytes: Vec<u8>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::Str("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::String("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::Bytes(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::String {
|
||||||
|
string: "\0".to_owned(),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("string"),
|
||||||
|
Token::ByteBuf(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Str("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::String("\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Bytes(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::ByteBuf(b"\0"),
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_de_tokens(
|
||||||
|
&Untagged::Bytes { bytes: vec![0] },
|
||||||
|
&[
|
||||||
|
Token::Struct {
|
||||||
|
name: "Untagged",
|
||||||
|
len: 1,
|
||||||
|
},
|
||||||
|
Token::Str("bytes"),
|
||||||
|
Token::Seq { len: Some(1) },
|
||||||
|
Token::U8(0),
|
||||||
|
Token::SeqEnd,
|
||||||
|
Token::StructEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contains_flatten() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum Data {
|
||||||
|
A {
|
||||||
|
a: i32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
flat: Flat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Flat {
|
||||||
|
b: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = Data::A {
|
||||||
|
a: 0,
|
||||||
|
flat: Flat { b: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&data,
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn contains_flatten_with_integer_key() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Untagged {
|
||||||
|
Variant {
|
||||||
|
#[serde(flatten)]
|
||||||
|
map: BTreeMap<u64, String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Untagged::Variant {
|
||||||
|
map: {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
map.insert(100, "BTreeMap".to_owned());
|
||||||
|
map
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::U64(100),
|
||||||
|
Token::Str("BTreeMap"),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expecting_message() {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
#[serde(expecting = "something strange...")]
|
||||||
|
enum Enum {
|
||||||
|
Untagged,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens_error::<Enum>(&[Token::Str("Untagged")], "something strange...");
|
||||||
|
}
|
||||||
+256
-43
@@ -3,15 +3,28 @@
|
|||||||
// types involved.
|
// types involved.
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![cfg_attr(feature = "unstable", feature(non_ascii_idents))]
|
#![allow(
|
||||||
|
confusable_idents,
|
||||||
#[macro_use]
|
unknown_lints,
|
||||||
extern crate serde_derive;
|
mixed_script_confusables,
|
||||||
|
clippy::derive_partial_eq_without_eq,
|
||||||
extern crate serde;
|
clippy::extra_unused_type_parameters,
|
||||||
use self::serde::de::{DeserializeOwned, Deserializer};
|
clippy::items_after_statements,
|
||||||
use self::serde::ser::{Serialize, Serializer};
|
clippy::missing_errors_doc,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
clippy::must_use_candidate,
|
||||||
|
// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
|
||||||
|
clippy::nonstandard_macro_braces,
|
||||||
|
clippy::ptr_arg,
|
||||||
|
clippy::too_many_lines,
|
||||||
|
clippy::trivially_copy_pass_by_ref,
|
||||||
|
clippy::type_repetition_in_bounds
|
||||||
|
)]
|
||||||
|
#![deny(clippy::collection_is_never_read)]
|
||||||
|
|
||||||
|
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
|
||||||
|
use serde::ser::{Serialize, Serializer};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::option::Option as StdOption;
|
use std::option::Option as StdOption;
|
||||||
@@ -246,6 +259,16 @@ fn test_gen() {
|
|||||||
}
|
}
|
||||||
assert::<VariantWithTraits2<X, X>>();
|
assert::<VariantWithTraits2<X, X>>();
|
||||||
|
|
||||||
|
type PhantomDataAlias<T> = PhantomData<T>;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(bound = "")]
|
||||||
|
struct PhantomDataWrapper<T> {
|
||||||
|
#[serde(default)]
|
||||||
|
field: PhantomDataAlias<T>,
|
||||||
|
}
|
||||||
|
assert::<PhantomDataWrapper<X>>();
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct CowStr<'a>(Cow<'a, str>);
|
struct CowStr<'a>(Cow<'a, str>);
|
||||||
assert::<CowStr>();
|
assert::<CowStr>();
|
||||||
@@ -265,62 +288,61 @@ fn test_gen() {
|
|||||||
}
|
}
|
||||||
assert::<EmptyEnumVariant>();
|
assert::<EmptyEnumVariant>();
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct NonAsciiIdents {
|
pub struct NonAsciiIdents {
|
||||||
σ: f64,
|
σ: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct EmptyBraced {}
|
pub struct EmptyBraced {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct EmptyBracedDenyUnknown {}
|
pub struct EmptyBracedDenyUnknown {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct BracedSkipAll {
|
pub struct BracedSkipAll {
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
f: u8,
|
f: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct BracedSkipAllDenyUnknown {
|
pub struct BracedSkipAllDenyUnknown {
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
f: u8,
|
f: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct EmptyTuple();
|
pub struct EmptyTuple();
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct EmptyTupleDenyUnknown();
|
pub struct EmptyTupleDenyUnknown();
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct TupleSkipAll(#[serde(skip_deserializing)] u8);
|
pub struct TupleSkipAll(#[serde(skip_deserializing)] u8);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
|
pub struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum EmptyEnum {}
|
pub enum EmptyEnum {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
enum EmptyEnumDenyUnknown {}
|
pub enum EmptyEnumDenyUnknown {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum EnumSkipAll {
|
pub enum EnumSkipAll {
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
Variant,
|
Variant,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum EmptyVariants {
|
pub enum EmptyVariants {
|
||||||
Braced {},
|
Braced {},
|
||||||
Tuple(),
|
Tuple(),
|
||||||
BracedSkip {
|
BracedSkip {
|
||||||
@@ -332,7 +354,7 @@ fn test_gen() {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
enum EmptyVariantsDenyUnknown {
|
pub enum EmptyVariantsDenyUnknown {
|
||||||
Braced {},
|
Braced {},
|
||||||
Tuple(),
|
Tuple(),
|
||||||
BracedSkip {
|
BracedSkip {
|
||||||
@@ -344,21 +366,21 @@ fn test_gen() {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct UnitDenyUnknown;
|
pub struct UnitDenyUnknown;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct EmptyArray {
|
pub struct EmptyArray {
|
||||||
empty: [X; 0],
|
empty: [X; 0],
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Or<A, B> {
|
pub enum Or<A, B> {
|
||||||
A(A),
|
A(A),
|
||||||
B(B),
|
B(B),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(untagged, remote = "Or")]
|
#[serde(untagged, remote = "Or")]
|
||||||
enum OrDef<A, B> {
|
pub enum OrDef<A, B> {
|
||||||
A(A),
|
A(A),
|
||||||
B(B),
|
B(B),
|
||||||
}
|
}
|
||||||
@@ -370,7 +392,7 @@ fn test_gen() {
|
|||||||
struct StrDef<'a>(&'a str);
|
struct StrDef<'a>(&'a str);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Remote<'a> {
|
pub struct Remote<'a> {
|
||||||
#[serde(with = "OrDef")]
|
#[serde(with = "OrDef")]
|
||||||
or: Or<u8, bool>,
|
or: Or<u8, bool>,
|
||||||
#[serde(borrow, with = "StrDef")]
|
#[serde(borrow, with = "StrDef")]
|
||||||
@@ -378,12 +400,14 @@ fn test_gen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum BorrowVariant<'a> {
|
pub enum BorrowVariant<'a> {
|
||||||
#[serde(borrow, with = "StrDef")]
|
#[serde(borrow, with = "StrDef")]
|
||||||
S(Str<'a>),
|
S(Str<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
mod vis {
|
mod vis {
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub struct S;
|
pub struct S;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -393,14 +417,14 @@ fn test_gen() {
|
|||||||
|
|
||||||
// This would not work if SDef::serialize / deserialize are private.
|
// This would not work if SDef::serialize / deserialize are private.
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct RemoteVisibility {
|
pub struct RemoteVisibility {
|
||||||
#[serde(with = "vis::SDef")]
|
#[serde(with = "vis::SDef")]
|
||||||
s: vis::S,
|
s: vis::S,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "Self")]
|
#[serde(remote = "Self")]
|
||||||
struct RemoteSelf;
|
pub struct RemoteSelf;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum ExternallyTaggedVariantWith {
|
enum ExternallyTaggedVariantWith {
|
||||||
@@ -524,19 +548,45 @@ fn test_gen() {
|
|||||||
assert::<FlattenWith>();
|
assert::<FlattenWith>();
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct StaticStrStruct<'a> {
|
pub struct Flatten<T> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
t: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct FlattenDenyUnknown<T> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
t: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SkipDeserializing<T> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct SkipDeserializingDenyUnknown<T> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StaticStrStruct<'a> {
|
||||||
a: &'a str,
|
a: &'a str,
|
||||||
b: &'static str,
|
b: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct StaticStrTupleStruct<'a>(&'a str, &'static str);
|
pub struct StaticStrTupleStruct<'a>(&'a str, &'static str);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct StaticStrNewtypeStruct(&'static str);
|
pub struct StaticStrNewtypeStruct(&'static str);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum StaticStrEnum<'a> {
|
pub enum StaticStrEnum<'a> {
|
||||||
Struct { a: &'a str, b: &'static str },
|
Struct { a: &'a str, b: &'static str },
|
||||||
Tuple(&'a str, &'static str),
|
Tuple(&'a str, &'static str),
|
||||||
Newtype(&'static str),
|
Newtype(&'static str),
|
||||||
@@ -607,7 +657,10 @@ fn test_gen() {
|
|||||||
|
|
||||||
mod restricted {
|
mod restricted {
|
||||||
mod inner {
|
mod inner {
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Restricted {
|
struct Restricted {
|
||||||
pub(super) a: usize,
|
pub(super) a: usize,
|
||||||
pub(in super::inner) b: usize,
|
pub(in super::inner) b: usize,
|
||||||
@@ -617,7 +670,7 @@ fn test_gen() {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "t", content = "c")]
|
#[serde(tag = "t", content = "c")]
|
||||||
enum AdjacentlyTaggedVoid {}
|
pub enum AdjacentlyTaggedVoid {}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
enum SkippedVariant<T> {
|
enum SkippedVariant<T> {
|
||||||
@@ -630,13 +683,13 @@ fn test_gen() {
|
|||||||
assert::<SkippedVariant<X>>();
|
assert::<SkippedVariant<X>>();
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct ImpliciltyBorrowedOption<'a> {
|
pub struct ImplicitlyBorrowedOption<'a> {
|
||||||
option: std::option::Option<&'a str>,
|
option: std::option::Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum UntaggedNewtypeVariantWith {
|
pub enum UntaggedNewtypeVariantWith {
|
||||||
Newtype(
|
Newtype(
|
||||||
#[serde(serialize_with = "ser_x")]
|
#[serde(serialize_with = "ser_x")]
|
||||||
#[serde(deserialize_with = "de_x")]
|
#[serde(deserialize_with = "de_x")]
|
||||||
@@ -646,7 +699,7 @@ fn test_gen() {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
struct TransparentWith {
|
pub struct TransparentWith {
|
||||||
#[serde(serialize_with = "ser_x")]
|
#[serde(serialize_with = "ser_x")]
|
||||||
#[serde(deserialize_with = "de_x")]
|
#[serde(deserialize_with = "de_x")]
|
||||||
x: X,
|
x: X,
|
||||||
@@ -654,16 +707,107 @@ fn test_gen() {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum UntaggedWithBorrow<'a> {
|
pub enum UntaggedWithBorrow<'a> {
|
||||||
Single(#[serde(borrow)] RelObject<'a>),
|
Single(
|
||||||
Many(#[serde(borrow)] Vec<RelObject<'a>>),
|
#[serde(borrow)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
RelObject<'a>,
|
||||||
|
),
|
||||||
|
Many(
|
||||||
|
#[serde(borrow)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Vec<RelObject<'a>>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct RelObject<'a> {
|
pub struct RelObject<'a> {
|
||||||
ty: &'a str,
|
ty: &'a str,
|
||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct FlattenSkipSerializing<T> {
|
||||||
|
#[serde(flatten, skip_serializing)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct FlattenSkipSerializingIf<T> {
|
||||||
|
#[serde(flatten, skip_serializing_if = "StdOption::is_none")]
|
||||||
|
flat: StdOption<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct FlattenSkipDeserializing<T> {
|
||||||
|
#[serde(flatten, skip_deserializing)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Inner<T> {
|
||||||
|
Builder {
|
||||||
|
s: T,
|
||||||
|
#[serde(flatten)]
|
||||||
|
o: T,
|
||||||
|
},
|
||||||
|
Default {
|
||||||
|
s: T,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/serde-rs/serde/issues/1804
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub enum Message {
|
||||||
|
#[serde(skip)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
String(String),
|
||||||
|
#[serde(other)]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Packed {
|
||||||
|
x: u8,
|
||||||
|
y: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! deriving {
|
||||||
|
($field:ty) => {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct MacroRules<'a> {
|
||||||
|
field: $field,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
deriving!(&'a str);
|
||||||
|
|
||||||
|
macro_rules! mac {
|
||||||
|
($($tt:tt)*) => {
|
||||||
|
$($tt)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct BorrowLifetimeInsideMacro<'a> {
|
||||||
|
#[serde(borrow = "'a")]
|
||||||
|
pub f: mac!(Cow<'a, str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct Struct {
|
||||||
|
#[serde(serialize_with = "vec_first_element")]
|
||||||
|
pub vec: Vec<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(bound(deserialize = "[&'de str; N]: Copy"))]
|
||||||
|
pub struct GenericUnitStruct<const N: usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@@ -737,3 +881,72 @@ where
|
|||||||
pub fn is_zero(n: &u8) -> bool {
|
pub fn is_zero(n: &u8) -> bool {
|
||||||
*n == 0
|
*n == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vec_first_element<T, S>(vec: &[T], serializer: S) -> StdResult<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: Serialize,
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
vec.first().serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "tag")]
|
||||||
|
pub enum InternallyTagged {
|
||||||
|
#[serde(deserialize_with = "deserialize_generic")]
|
||||||
|
Unit,
|
||||||
|
|
||||||
|
#[serde(deserialize_with = "deserialize_generic")]
|
||||||
|
Newtype(i32),
|
||||||
|
|
||||||
|
#[serde(deserialize_with = "deserialize_generic")]
|
||||||
|
Struct { f1: String, f2: u8 },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_generic<'de, T, D>(deserializer: D) -> StdResult<T, D::Error>
|
||||||
|
where
|
||||||
|
T: Deserialize<'de>,
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
T::deserialize(deserializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct RemotePacked {
|
||||||
|
pub a: u16,
|
||||||
|
pub b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[serde(remote = "RemotePacked")]
|
||||||
|
pub struct RemotePackedDef {
|
||||||
|
a: u16,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RemotePackedDef {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct RemotePackedNonCopy {
|
||||||
|
pub a: u16,
|
||||||
|
pub b: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[repr(packed)]
|
||||||
|
#[serde(remote = "RemotePackedNonCopy")]
|
||||||
|
pub struct RemotePackedNonCopyDef {
|
||||||
|
a: u16,
|
||||||
|
b: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RemotePackedNonCopyDef {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,75 +1,188 @@
|
|||||||
#[macro_use]
|
//! Tests for `#[serde(field_identifier)]` and `#[serde(variant_identifier)]`
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
extern crate serde_test;
|
#![allow(clippy::derive_partial_eq_without_eq)]
|
||||||
use serde_test::{assert_de_tokens, Token};
|
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
|
||||||
|
|
||||||
|
mod variant_identifier {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_variant_identifier() {
|
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
#[serde(variant_identifier)]
|
#[serde(variant_identifier)]
|
||||||
enum V {
|
enum V {
|
||||||
Aaa,
|
Aaa,
|
||||||
|
#[serde(alias = "Ccc", alias = "Ddd")]
|
||||||
Bbb,
|
Bbb,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
|
#[test]
|
||||||
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
|
fn variant1() {
|
||||||
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
|
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
|
||||||
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
|
||||||
|
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
|
||||||
|
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aliases() {
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::U8(1)]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::U16(1)]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::U32(1)]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::U64(1)]);
|
||||||
|
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Str("Bbb")]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Bbb")]);
|
||||||
|
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Str("Ccc")]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ccc")]);
|
||||||
|
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Str("Ddd")]);
|
||||||
|
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ddd")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unknown() {
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::U8(42)],
|
||||||
|
"invalid value: integer `42`, expected variant index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::U16(42)],
|
||||||
|
"invalid value: integer `42`, expected variant index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::U32(42)],
|
||||||
|
"invalid value: integer `42`, expected variant index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::U64(42)],
|
||||||
|
"invalid value: integer `42`, expected variant index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::Str("Unknown")],
|
||||||
|
"unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<V>(
|
||||||
|
&[Token::Bytes(b"Unknown")],
|
||||||
|
"unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
mod field_identifier {
|
||||||
fn test_field_identifier() {
|
use super::*;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
#[serde(field_identifier, rename_all = "snake_case")]
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
enum F {
|
enum F {
|
||||||
Aaa,
|
Aaa,
|
||||||
|
#[serde(alias = "ccc", alias = "ddd")]
|
||||||
Bbb,
|
Bbb,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]);
|
#[test]
|
||||||
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]);
|
fn field1() {
|
||||||
}
|
assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
|
||||||
|
assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
|
||||||
#[test]
|
assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
|
||||||
fn test_unit_fallthrough() {
|
assert_de_tokens(&F::Aaa, &[Token::U64(0)]);
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]);
|
||||||
#[serde(field_identifier, rename_all = "snake_case")]
|
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]);
|
||||||
enum F {
|
|
||||||
Aaa,
|
|
||||||
Bbb,
|
|
||||||
#[serde(other)]
|
|
||||||
Other,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&F::Other, &[Token::Str("x")]);
|
#[test]
|
||||||
}
|
fn aliases() {
|
||||||
|
assert_de_tokens(&F::Bbb, &[Token::U8(1)]);
|
||||||
|
assert_de_tokens(&F::Bbb, &[Token::U16(1)]);
|
||||||
|
assert_de_tokens(&F::Bbb, &[Token::U32(1)]);
|
||||||
|
assert_de_tokens(&F::Bbb, &[Token::U64(1)]);
|
||||||
|
|
||||||
#[test]
|
assert_de_tokens(&F::Bbb, &[Token::Str("bbb")]);
|
||||||
fn test_newtype_fallthrough() {
|
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"bbb")]);
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
|
||||||
#[serde(field_identifier, rename_all = "snake_case")]
|
assert_de_tokens(&F::Bbb, &[Token::Str("ccc")]);
|
||||||
enum F {
|
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ccc")]);
|
||||||
Aaa,
|
|
||||||
Bbb,
|
assert_de_tokens(&F::Bbb, &[Token::Str("ddd")]);
|
||||||
Other(String),
|
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ddd")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
|
#[test]
|
||||||
}
|
fn unknown() {
|
||||||
|
assert_de_tokens_error::<F>(
|
||||||
#[test]
|
&[Token::U8(42)],
|
||||||
fn test_newtype_fallthrough_generic() {
|
"invalid value: integer `42`, expected field index 0 <= i < 2",
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
);
|
||||||
#[serde(field_identifier, rename_all = "snake_case")]
|
assert_de_tokens_error::<F>(
|
||||||
enum F<T> {
|
&[Token::U16(42)],
|
||||||
Aaa,
|
"invalid value: integer `42`, expected field index 0 <= i < 2",
|
||||||
Bbb,
|
);
|
||||||
Other(T),
|
assert_de_tokens_error::<F>(
|
||||||
|
&[Token::U32(42)],
|
||||||
|
"invalid value: integer `42`, expected field index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<F>(
|
||||||
|
&[Token::U64(42)],
|
||||||
|
"invalid value: integer `42`, expected field index 0 <= i < 2",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<F>(
|
||||||
|
&[Token::Str("unknown")],
|
||||||
|
"unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<F>(
|
||||||
|
&[Token::Bytes(b"unknown")],
|
||||||
|
"unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
|
#[test]
|
||||||
|
fn unit_fallthrough() {
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
|
enum F {
|
||||||
|
Aaa,
|
||||||
|
Bbb,
|
||||||
|
#[serde(other)]
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(&F::Other, &[Token::U8(42)]);
|
||||||
|
assert_de_tokens(&F::Other, &[Token::U16(42)]);
|
||||||
|
assert_de_tokens(&F::Other, &[Token::U32(42)]);
|
||||||
|
assert_de_tokens(&F::Other, &[Token::U64(42)]);
|
||||||
|
assert_de_tokens(&F::Other, &[Token::Str("x")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_fallthrough() {
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
|
enum F {
|
||||||
|
Aaa,
|
||||||
|
Bbb,
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newtype_fallthrough_generic() {
|
||||||
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
|
enum F<T> {
|
||||||
|
Aaa,
|
||||||
|
Bbb,
|
||||||
|
Other(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]);
|
||||||
|
assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]);
|
||||||
|
assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]);
|
||||||
|
assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]);
|
||||||
|
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#![allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
|
||||||
|
use serde::de::value::{Error, MapDeserializer, SeqDeserializer};
|
||||||
|
use serde::de::{
|
||||||
|
Deserialize, DeserializeSeed, Deserializer, EnumAccess, IgnoredAny, IntoDeserializer,
|
||||||
|
VariantAccess, Visitor,
|
||||||
|
};
|
||||||
|
use serde::forward_to_deserialize_any;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Deserialize)]
|
||||||
|
enum Target {
|
||||||
|
Unit,
|
||||||
|
Newtype(i32),
|
||||||
|
Tuple(i32, i32),
|
||||||
|
Struct { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Enum(&'static str);
|
||||||
|
|
||||||
|
impl<'de> Deserializer<'de> for Enum {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_enum(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> EnumAccess<'de> for Enum {
|
||||||
|
type Error = Error;
|
||||||
|
type Variant = Self;
|
||||||
|
|
||||||
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||||
|
where
|
||||||
|
V: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
let v = seed.deserialize(self.0.into_deserializer())?;
|
||||||
|
Ok((v, self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> VariantAccess<'de> for Enum {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn unit_variant(self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(10i32.into_deserializer())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
let seq = SeqDeserializer::new(vec![1i32, 2].into_iter());
|
||||||
|
visitor.visit_seq(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_variant<V>(
|
||||||
|
self,
|
||||||
|
_fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
let map = MapDeserializer::new(vec![("a", 10i32)].into_iter());
|
||||||
|
visitor.visit_map(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialize_enum() {
|
||||||
|
// First just make sure the Deserializer impl works
|
||||||
|
assert_eq!(Target::Unit, Target::deserialize(Enum("Unit")).unwrap());
|
||||||
|
assert_eq!(
|
||||||
|
Target::Newtype(10),
|
||||||
|
Target::deserialize(Enum("Newtype")).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Target::Tuple(1, 2),
|
||||||
|
Target::deserialize(Enum("Tuple")).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Target::Struct { a: 10 },
|
||||||
|
Target::deserialize(Enum("Struct")).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now try IgnoredAny
|
||||||
|
IgnoredAny::deserialize(Enum("Unit")).unwrap();
|
||||||
|
IgnoredAny::deserialize(Enum("Newtype")).unwrap();
|
||||||
|
IgnoredAny::deserialize(Enum("Tuple")).unwrap();
|
||||||
|
IgnoredAny::deserialize(Enum("Struct")).unwrap();
|
||||||
|
}
|
||||||
+157
-1041
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,23 @@
|
|||||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
#![allow(clippy::redundant_field_names)]
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(redundant_field_names))]
|
|
||||||
|
|
||||||
#[macro_use]
|
use serde_derive::{Deserialize, Serialize};
|
||||||
extern crate serde_derive;
|
|
||||||
|
|
||||||
mod remote {
|
mod remote {
|
||||||
pub struct Unit;
|
pub struct Unit;
|
||||||
|
|
||||||
pub struct PrimitivePriv(u8);
|
pub struct PrimitivePriv(u8);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct PrimitivePub(pub u8);
|
pub struct PrimitivePub(pub u8);
|
||||||
|
|
||||||
pub struct NewtypePriv(Unit);
|
pub struct NewtypePriv(Unit);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct NewtypePub(pub Unit);
|
pub struct NewtypePub(pub Unit);
|
||||||
|
|
||||||
pub struct TuplePriv(u8, Unit);
|
pub struct TuplePriv(u8, Unit);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct TuplePub(pub u8, pub Unit);
|
pub struct TuplePub(pub u8, pub Unit);
|
||||||
|
|
||||||
pub struct StructPriv {
|
pub struct StructPriv {
|
||||||
@@ -24,6 +25,7 @@ mod remote {
|
|||||||
b: Unit,
|
b: Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct StructPub {
|
pub struct StructPub {
|
||||||
pub a: u8,
|
pub a: u8,
|
||||||
pub b: Unit,
|
pub b: Unit,
|
||||||
@@ -76,9 +78,26 @@ mod remote {
|
|||||||
&self.b
|
&self.b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StructGeneric<T> {
|
||||||
|
pub value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> StructGeneric<T> {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_value(&self) -> &T {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum EnumGeneric<T> {
|
||||||
|
Variant(T),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Test {
|
struct Test {
|
||||||
#[serde(with = "UnitDef")]
|
#[serde(with = "UnitDef")]
|
||||||
unit: remote::Unit,
|
unit: remote::Unit,
|
||||||
@@ -106,10 +125,20 @@ struct Test {
|
|||||||
|
|
||||||
#[serde(with = "StructPubDef")]
|
#[serde(with = "StructPubDef")]
|
||||||
struct_pub: remote::StructPub,
|
struct_pub: remote::StructPub,
|
||||||
|
|
||||||
|
#[serde(with = "StructConcrete")]
|
||||||
|
struct_concrete: remote::StructGeneric<u8>,
|
||||||
|
|
||||||
|
#[serde(with = "EnumConcrete")]
|
||||||
|
enum_concrete: remote::EnumGeneric<u8>,
|
||||||
|
|
||||||
|
#[serde(with = "ErrorKindDef")]
|
||||||
|
io_error_kind: ErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::Unit")]
|
#[serde(remote = "remote::Unit")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct UnitDef;
|
struct UnitDef;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -118,6 +147,7 @@ struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::PrimitivePub")]
|
#[serde(remote = "remote::PrimitivePub")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct PrimitivePubDef(u8);
|
struct PrimitivePubDef(u8);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -126,6 +156,7 @@ struct NewtypePrivDef(#[serde(getter = "remote::NewtypePriv::get", with = "UnitD
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::NewtypePub")]
|
#[serde(remote = "remote::NewtypePub")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
|
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -137,6 +168,7 @@ struct TuplePrivDef(
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::TuplePub")]
|
#[serde(remote = "remote::TuplePub")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
|
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -152,6 +184,7 @@ struct StructPrivDef {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "remote::StructPub")]
|
#[serde(remote = "remote::StructPub")]
|
||||||
|
#[allow(dead_code)]
|
||||||
struct StructPubDef {
|
struct StructPubDef {
|
||||||
a: u8,
|
a: u8,
|
||||||
|
|
||||||
@@ -159,6 +192,46 @@ struct StructPubDef {
|
|||||||
b: remote::Unit,
|
b: remote::Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "remote::StructGeneric")]
|
||||||
|
struct StructGenericWithGetterDef<T> {
|
||||||
|
#[serde(getter = "remote::StructGeneric::get_value")]
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "remote::StructGeneric<u8>")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct StructConcrete {
|
||||||
|
value: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "remote::EnumGeneric<u8>")]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum EnumConcrete {
|
||||||
|
Variant(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum ErrorKind {
|
||||||
|
NotFound,
|
||||||
|
PermissionDenied,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
ConnectionRefused,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "ErrorKind")]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum ErrorKindDef {
|
||||||
|
NotFound,
|
||||||
|
PermissionDenied,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PrimitivePrivDef> for remote::PrimitivePriv {
|
impl From<PrimitivePrivDef> for remote::PrimitivePriv {
|
||||||
fn from(def: PrimitivePrivDef) -> Self {
|
fn from(def: PrimitivePrivDef) -> Self {
|
||||||
remote::PrimitivePriv::new(def.0)
|
remote::PrimitivePriv::new(def.0)
|
||||||
@@ -182,3 +255,9 @@ impl From<StructPrivDef> for remote::StructPriv {
|
|||||||
remote::StructPriv::new(def.a, def.b)
|
remote::StructPriv::new(def.a, def.b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<StructGenericWithGetterDef<T>> for remote::StructGeneric<T> {
|
||||||
|
fn from(def: StructGenericWithGetterDef<T>) -> Self {
|
||||||
|
remote::StructGeneric { value: def.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
extern crate serde_test;
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
use self::serde_test::{assert_tokens, Configure, Token};
|
|
||||||
|
|
||||||
use std::net;
|
use std::net;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -12,10 +10,12 @@ fn ip_addr_roundtrip() {
|
|||||||
assert_tokens(
|
assert_tokens(
|
||||||
&net::IpAddr::from(*b"1234").compact(),
|
&net::IpAddr::from(*b"1234").compact(),
|
||||||
&seq![
|
&seq![
|
||||||
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
|
Token::NewtypeVariant {
|
||||||
|
name: "IpAddr",
|
||||||
|
variant: "V4"
|
||||||
|
},
|
||||||
Token::Tuple { len: 4 },
|
Token::Tuple { len: 4 },
|
||||||
seq b"1234".iter().map(|&b| Token::U8(b)),
|
b"1234".iter().copied().map(Token::U8),
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -26,14 +26,14 @@ fn socket_addr_roundtrip() {
|
|||||||
assert_tokens(
|
assert_tokens(
|
||||||
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
|
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
|
||||||
&seq![
|
&seq![
|
||||||
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
|
Token::NewtypeVariant {
|
||||||
|
name: "SocketAddr",
|
||||||
|
variant: "V6"
|
||||||
|
},
|
||||||
Token::Tuple { len: 2 },
|
Token::Tuple { len: 2 },
|
||||||
|
|
||||||
Token::Tuple { len: 16 },
|
Token::Tuple { len: 16 },
|
||||||
seq b"1234567890123456".iter().map(|&b| Token::U8(b)),
|
b"1234567890123456".iter().copied().map(Token::U8),
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
|
|
||||||
Token::U16(1234),
|
Token::U16(1234),
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#![allow(clippy::used_underscore_binding)]
|
||||||
|
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_self() {
|
||||||
|
pub trait Trait {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Generics<T: Trait<Assoc = Self>>
|
||||||
|
where
|
||||||
|
Self: Trait<Assoc = Self>,
|
||||||
|
<Self as Trait>::Assoc: Sized,
|
||||||
|
{
|
||||||
|
_f: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Trait<Assoc = Self>> Trait for Generics<T> {
|
||||||
|
type Assoc = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Struct {
|
||||||
|
_f1: Box<Self>,
|
||||||
|
_f2: Box<<Self as Trait>::Assoc>,
|
||||||
|
_f4: [(); Self::ASSOC],
|
||||||
|
_f5: [(); Self::assoc()],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Struct {
|
||||||
|
const ASSOC: usize = 1;
|
||||||
|
const fn assoc() -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Struct {
|
||||||
|
type Assoc = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Tuple(
|
||||||
|
Box<Self>,
|
||||||
|
Box<<Self as Trait>::Assoc>,
|
||||||
|
[(); Self::ASSOC],
|
||||||
|
[(); Self::assoc()],
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Tuple {
|
||||||
|
const ASSOC: usize = 1;
|
||||||
|
const fn assoc() -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Tuple {
|
||||||
|
type Assoc = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum Enum {
|
||||||
|
Struct {
|
||||||
|
_f1: Box<Self>,
|
||||||
|
_f2: Box<<Self as Trait>::Assoc>,
|
||||||
|
_f4: [(); Self::ASSOC],
|
||||||
|
_f5: [(); Self::assoc()],
|
||||||
|
},
|
||||||
|
Tuple(
|
||||||
|
Box<Self>,
|
||||||
|
Box<<Self as Trait>::Assoc>,
|
||||||
|
[(); Self::ASSOC],
|
||||||
|
[(); Self::assoc()],
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Enum {
|
||||||
|
const ASSOC: usize = 1;
|
||||||
|
const fn assoc() -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Enum {
|
||||||
|
type Assoc = Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
+728
-427
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