mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 00:08:01 +00:00
Compare commits
842 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1385aac208 | |||
| b279ebb244 | |||
| 039ebc63a1 | |||
| defd8853b1 | |||
| 7d73089b7c | |||
| 06dcbbbaba | |||
| ad62a6895c | |||
| ced57a9e5f | |||
| b5f083e6f4 | |||
| 4de20bd48d | |||
| 9083cf4b00 | |||
| c17bc6c49c | |||
| e883dc1bba | |||
| 412bedc192 | |||
| 4615e428e8 | |||
| 26fec05611 | |||
| fdb51cc7dc | |||
| 5510f758f8 | |||
| 922fadf7e3 | |||
| 6bbc415fdf | |||
| b13875dd97 | |||
| ac1b25e91d | |||
| 1335f85213 | |||
| 0a4d536253 | |||
| 7dba1e303d | |||
| 0ea9d73fdf | |||
| a64aaeeb3b | |||
| 320897679b | |||
| 3d5141a2f1 | |||
| 656ea96c65 | |||
| 5302482596 | |||
| 7ada27014d | |||
| 4fa2a50f62 | |||
| 0c5f20c148 | |||
| aa2bbb4704 | |||
| 16d1265e17 | |||
| f09320b293 | |||
| 3b4803115b | |||
| fa5f0f4541 | |||
| 4b7f55bd42 | |||
| 593bcb087d | |||
| f58000cb41 | |||
| 01b86d5ce4 | |||
| c80f9238d7 | |||
| 62850bf832 | |||
| 9f114548f4 | |||
| 8890061f82 | |||
| 2c05518810 | |||
| 4aeb0df88f | |||
| 6550231a51 | |||
| ea0012fc5a | |||
| d6b62b9417 | |||
| 2ee347c5a5 | |||
| 4305260174 | |||
| 35aae92b56 | |||
| f3f26796c7 | |||
| d1460e1f0d | |||
| dfd81323d5 | |||
| 368961e961 | |||
| f9c6f0ab62 | |||
| b2b36e1764 | |||
| 4ad140ea70 | |||
| 67777eb585 | |||
| b4e51fcc77 | |||
| be7fe2a5eb | |||
| b4076f4577 | |||
| c4181f46be | |||
| 8c0efc3d77 | |||
| 7e3efaf6c5 | |||
| 12fe42ed45 | |||
| 7cd4f49c76 | |||
| ff9c85d47f | |||
| 0025ef9aba | |||
| 536bdd77a0 | |||
| 6993b983d2 | |||
| 4bfeb05f22 | |||
| 4687c1b52b | |||
| a58abae193 | |||
| 0bc9c729b3 | |||
| dc921892be | |||
| 62557731c3 | |||
| ab62cd3b28 | |||
| 30824e9f61 | |||
| eecc0870fc | |||
| 6475e73b05 | |||
| 697234517d | |||
| 3cd9d071c2 | |||
| 9dc05c36f0 | |||
| 972cc06fed | |||
| 20013464f8 | |||
| 2009b4da5f | |||
| 0b72c86a35 | |||
| 94b857057b | |||
| 979df3427b | |||
| 978d64993e | |||
| 5098609935 | |||
| 6374467f02 | |||
| 1f9fc61b98 | |||
| 3859f58d9b | |||
| aac1c65033 | |||
| d8120e19bc | |||
| ed425b3a6f | |||
| d1297deb36 | |||
| f263e3fcec | |||
| 40479336c1 | |||
| 6ca4dd2c4a | |||
| c04c233838 | |||
| 175c638fdc | |||
| 97eff8e875 | |||
| 47676cdb49 | |||
| 93bddb361e | |||
| adb1c9540d | |||
| 0e1d065402 | |||
| 8c3b52e308 | |||
| 3f0d3453d8 | |||
| b27a27ce22 | |||
| 80c0600657 | |||
| 77f9e63661 | |||
| b78f434086 | |||
| 893c0578dd | |||
| cb2b92f828 | |||
| 47a4ffbd31 | |||
| d82d1707d6 | |||
| 89278996c5 | |||
| ecef937e26 | |||
| bceda5fb18 | |||
| f46a08b04e | |||
| f3cb7c7a32 | |||
| af795e2e54 | |||
| 6aa07fe0d6 | |||
| c455720f81 | |||
| b07a208716 | |||
| df93fab5fa | |||
| 1a972d2105 | |||
| 6d1807bb4a | |||
| b37cf858ce | |||
| 5f8fa33756 | |||
| f3f006f411 | |||
| 607966dcf7 | |||
| 6a8c39b2aa | |||
| 382f3c2771 | |||
| 85ca12a8c3 | |||
| 541f9180cf | |||
| 3c4961c48e | |||
| 184264ee92 | |||
| 6050229e7e | |||
| e1db820c9f | |||
| 0081cc961d | |||
| 9bc05803fe | |||
| 8d113e67d6 | |||
| 6e206ce053 | |||
| 47fc9af472 | |||
| 1651f86d56 | |||
| 1157ac0118 | |||
| 202c10147e | |||
| 9f38ca032e | |||
| 00178ba795 | |||
| 24700ebeb6 | |||
| f06001c086 | |||
| ec773fb7db | |||
| da8b457f66 | |||
| a6e94e7122 | |||
| 629bf7b354 | |||
| 4415d10c61 | |||
| def8d6e8af | |||
| 2e824e9aba | |||
| fd14332729 | |||
| c413775574 | |||
| 5efb22ebee | |||
| 3e535325e1 | |||
| 5653e5b15c | |||
| 8d85860064 | |||
| eed18ffab2 | |||
| f8e1fa8ebc | |||
| 860241aa88 | |||
| 6f6c60867d | |||
| 77376f39ea | |||
| 302fac91a3 | |||
| 9c659d9d86 | |||
| 21698f264a | |||
| ba002e1119 | |||
| 8b44eb8bfc | |||
| d82a0cc5ff | |||
| 801fd1dc19 | |||
| 222779d46c | |||
| b1c1d964e1 | |||
| b77cfb635d | |||
| c42c08a25b | |||
| 48997cbb5b | |||
| d8ccd8809e | |||
| d2b65e0a5d | |||
| 7c04c98e0e | |||
| a2fa4c2570 | |||
| 42430902e2 | |||
| 23e2e92237 | |||
| 273b2c11c6 | |||
| c1602a4d76 | |||
| c23be3f855 | |||
| 5c9c97c0ce | |||
| e5ed440136 | |||
| d45ca2f5e4 | |||
| d7f9f8209d | |||
| 4a2612ecff | |||
| 05b22a06d7 | |||
| 3145bcc46e | |||
| 2b18b57d84 | |||
| 5520202262 | |||
| 3d647f4063 | |||
| 0fde3c2ee8 | |||
| 27f935f036 | |||
| 99614c7266 | |||
| bb2ecb3bc4 | |||
| 96393bfcc7 | |||
| 1d92569abc | |||
| e4ef087735 | |||
| 695c3eedcb | |||
| 50c636a923 | |||
| 5b884b5bf9 | |||
| 8637dda60f | |||
| abeea89147 | |||
| 6e324e887d | |||
| 7c596c7136 | |||
| f02dbf381b | |||
| 7cf184624a | |||
| c5a3128492 | |||
| 205f606962 | |||
| ad40f976db | |||
| 58d52e784b | |||
| d44f12907b | |||
| 61b167be9a | |||
| f1af2dc5ab | |||
| ebc61baab2 | |||
| ffcde25b6e | |||
| 2f57cecf13 | |||
| bfdcbae9db | |||
| ca41e16e92 | |||
| 352fe7b451 | |||
| 49e302d17d | |||
| b8602a7e43 | |||
| a8c8c2028e | |||
| d1833c5602 | |||
| b4ef7ac323 | |||
| ebf80ac965 | |||
| 112dfd7428 | |||
| b692923321 | |||
| 9e8cda4c37 | |||
| 5457394f5b | |||
| 6627540dd6 | |||
| 5ae06bba49 | |||
| 571bb8caed | |||
| 299cd2dbd0 | |||
| 583c0d8d14 | |||
| 07d07347b3 | |||
| 77b07f3fbf | |||
| 1bd2c6129c | |||
| 39413c8ce7 | |||
| b4dbae250b | |||
| 5a91ac5ba5 | |||
| 7ad836e6a9 | |||
| 72ecb9064c | |||
| 23c6eb3b40 | |||
| b8c9a66d75 | |||
| 56b2e39dda | |||
| 5bc805329e | |||
| 69dd3215f4 | |||
| a7a7a31809 | |||
| af9996aa9a | |||
| 0d4d47c398 | |||
| 30361ac6d0 | |||
| 3f75239bfb | |||
| 8dd5605a40 | |||
| f288a41768 | |||
| f4b78e202a | |||
| 0ddebe0317 | |||
| 9fc526b788 | |||
| a799ea171c | |||
| d6f07f2f47 | |||
| f9946ee0ca | |||
| a164f52315 | |||
| 8bba8447ef | |||
| 9db784bccd | |||
| 9317bc5afa | |||
| a185df1e77 | |||
| 1bdf5ecec4 | |||
| 59017aa19b | |||
| 6b4625dcbb | |||
| 6e01f220b1 | |||
| 64573319f9 | |||
| 3d64df6e87 | |||
| cc2558b0dc | |||
| 5c41661bce | |||
| dd6914a203 | |||
| 63623eb3b3 | |||
| ddc4b50d4d | |||
| b313f947dc | |||
| 16bc9fb99e | |||
| 34eaab00f7 | |||
| 6024e717fb | |||
| ef4dd6c0ec | |||
| f7ed967db1 | |||
| 613e46b0ee | |||
| b2d2e96267 | |||
| ae0373643c | |||
| 7aeabddd2f | |||
| 9df8f5ecc0 | |||
| c4fad2883b | |||
| 9cfcd78c87 | |||
| 4751627f1c | |||
| ae59c6b6d2 | |||
| 4973d7a62d | |||
| ed6a1de311 | |||
| ab234be025 | |||
| ee75e6c0e9 | |||
| c2b390fe63 | |||
| 56d5d7f761 | |||
| 0b89bc920e | |||
| 0dac13e4db | |||
| 0c2e91f28a | |||
| 13e7bee0e6 | |||
| 65104aca9c | |||
| 9360094ba7 | |||
| 3700779bfa | |||
| d9e894911f | |||
| 85e3ddc2b8 | |||
| ccae35d92a | |||
| 61ca928325 | |||
| a93f2ebff0 | |||
| a45f1ae915 | |||
| 9641978481 | |||
| ffd2017c6f | |||
| b7eb42aa6b | |||
| 750f8ba299 | |||
| 49cdef074d | |||
| aa86b04714 | |||
| c887a0b472 | |||
| 34936be574 | |||
| e354dd0c7f | |||
| bc221abb04 | |||
| ab5e8780ab | |||
| 0c34e06e51 | |||
| 4a0c4e0c25 | |||
| 8c34e0940f | |||
| eb6bf16a51 | |||
| 797d049db5 | |||
| d61a373f12 | |||
| e0eea551b4 | |||
| c650a92bf7 | |||
| f218f4d7bf | |||
| 8c0a2015be | |||
| 4773863e3a | |||
| 80cd9c7617 | |||
| 436cafb0a3 | |||
| 98bb02e9b4 | |||
| 142439088c | |||
| ce81288235 | |||
| 88d5fe6bfd | |||
| 9a2c352025 | |||
| 61c90cb8cb | |||
| 66e8b0a0cd | |||
| 9e7a3437d9 | |||
| 7ac8d4f9ae | |||
| 501bae42f5 | |||
| 7a0397451e | |||
| 16787318d1 | |||
| f4ae0888c8 | |||
| 213071fe5c | |||
| cfd26c6fda | |||
| 23fa83941e | |||
| 88f5b9511d | |||
| d537f1e1f0 | |||
| f6ac232580 | |||
| aad7a7987f | |||
| b24ad76880 | |||
| 5796f1a0f5 | |||
| 6437167930 | |||
| f98daaa250 | |||
| b8a40551a2 | |||
| 40db31691a | |||
| ab68132b1f | |||
| e70bbd9dde | |||
| d5e5c520ac | |||
| 1b9a096fa7 | |||
| 39e05ffad2 | |||
| 78fab25c5c | |||
| 2a557a1e36 | |||
| ab0848f780 | |||
| 2b1303f59c | |||
| 7f9ba155cb | |||
| a4e0c2f055 | |||
| 3bbf70575b | |||
| ad680cbd44 | |||
| ff0cfb1f1f | |||
| 9b08915a18 | |||
| 501aa3ee1d | |||
| eebf0f8db8 | |||
| a7e4911ddb | |||
| eb08f037f5 | |||
| aa03fd5d1a | |||
| e198afb0c1 | |||
| bc8de251cf | |||
| 99e8686189 | |||
| 826f656e28 | |||
| ab7c003b64 | |||
| 422191fcb0 | |||
| 4ba748c902 | |||
| 14ed6f2dab | |||
| 30606a43aa | |||
| 9be3d32016 | |||
| 5daf1b89a1 | |||
| f8f5d0ca2f | |||
| 57873cce28 | |||
| 4ed0362c8e | |||
| 4cecaf8d02 | |||
| 50c696aabe | |||
| 2f58a20bc6 | |||
| 030459a040 | |||
| e9b530a000 | |||
| ea1a729088 | |||
| 857dcea774 | |||
| b98a9a8f9b | |||
| 3b135431fd | |||
| 945d12c0b4 | |||
| e36915300f | |||
| 85c05d301a | |||
| c2474bf6ee | |||
| a52f436788 | |||
| ad3335e5d6 | |||
| 4b00de0e22 | |||
| 8403fa018e | |||
| 0e9f1b42de | |||
| 0085d05e55 | |||
| 2eed855bff | |||
| c3eced410f | |||
| 8a630fea7c | |||
| 2e597ed3f0 | |||
| 0963121beb | |||
| 15b2714058 | |||
| 9ce107de25 | |||
| e47284c0e0 | |||
| 800620e2aa | |||
| 40c670e625 | |||
| ba260b0e5f | |||
| 8452e313cc | |||
| 0dccbb1f11 | |||
| deca49315a | |||
| 95407a4ca5 | |||
| 2fe9a860cd | |||
| e67d941b78 | |||
| d4042872f5 | |||
| 64af86b830 | |||
| 370c8a91cb | |||
| 972da59ebc | |||
| a42008f695 | |||
| e4ea2a56e9 | |||
| 7650a48fdd | |||
| d665a2f2b2 | |||
| 44e23254c9 | |||
| 552971196d | |||
| 0681cd5003 | |||
| d965367238 | |||
| a6df35b3d2 | |||
| 9fc180e62f | |||
| 5b815b7001 | |||
| 4831482695 | |||
| d3e5dd9cd7 | |||
| 26098ed877 | |||
| 42ed62cf24 | |||
| 9f0973aff7 | |||
| ccec002bf3 | |||
| f36a1e0895 | |||
| e6487cf6fa | |||
| 4f2e8d5dbb | |||
| 1c2a4bff1c | |||
| 85bccf42b6 | |||
| 959fee024f | |||
| 8ede8c8e2a | |||
| 83537c95e1 | |||
| fa9057fa31 | |||
| 0084d82a50 | |||
| b504b08782 | |||
| 775e8154e7 | |||
| 9c679d9082 | |||
| b0f9d2a0ba | |||
| f39b1db96a | |||
| 9ecb0839de | |||
| 8a4c116812 | |||
| 1d3e921ba6 | |||
| 8e8694261b | |||
| 4fdba725fe | |||
| 75eed8cdde | |||
| 6801a13650 | |||
| 25ab84d4b9 | |||
| e43d3f3e4f | |||
| b37d47c987 | |||
| eec7101894 | |||
| 5dd327fb02 | |||
| fd3d1396d3 | |||
| c47b4c8e0b | |||
| 2d793b82f6 | |||
| 237be46e29 | |||
| 3d7aad1e7b | |||
| e792874369 | |||
| 1669c69714 | |||
| 4d5e450054 | |||
| 26b22e647d | |||
| cda1fc46b0 | |||
| c68b959696 | |||
| eab80172e4 | |||
| c1259fbc87 | |||
| 58e30eaee4 | |||
| bafa941004 | |||
| f347b2d363 | |||
| 3f9fc49cca | |||
| c913527944 | |||
| 8fafc7420c | |||
| bea1c5b0f5 | |||
| aa37caf216 | |||
| 2440b59aae | |||
| 873cfbe9ab | |||
| c96efcb87a | |||
| b53026a21b | |||
| c7901e532e | |||
| 2af0701be6 | |||
| ae79451b7a | |||
| b220f264a5 | |||
| 1a2b3815ef | |||
| 6fbf40b83c | |||
| 1d6ecf3c2c | |||
| d7ccef0cac | |||
| 2d465415c5 | |||
| bc2d637112 | |||
| cf1cdadc77 | |||
| 4a9cb3395d | |||
| dfa6623a24 | |||
| a8adac6b93 | |||
| b9b7922ef1 | |||
| a369ee156f | |||
| d1253cb193 | |||
| bc982f9757 | |||
| 0240814677 | |||
| 670be2ce2f | |||
| c893e3e872 | |||
| fe8141fd70 | |||
| aa750d2bf3 | |||
| 4cea214da2 | |||
| 15341780a2 | |||
| 4767ca3f5d | |||
| 26a6ba177c | |||
| 974c8434e9 | |||
| 0734b44a3a | |||
| d0f846182b | |||
| 7a7d4c6364 | |||
| c567e749ef | |||
| b8a6e68322 | |||
| 6279b0d930 | |||
| a778425d0f | |||
| faaf5ee115 | |||
| 86deb8db79 | |||
| d4d2061a2e | |||
| c202ce13dc | |||
| 1c9478bfa6 | |||
| 739ad64c7c | |||
| 3eef7c87c9 | |||
| e0c040a3a2 | |||
| c13a37d4db | |||
| 4354aab93a | |||
| 691e304fff | |||
| 13463e25c2 | |||
| 54bbf81dfc | |||
| cdfd445528 | |||
| 30e8c84d01 | |||
| a35bde49c6 | |||
| f9535a4d67 | |||
| 6d55501dab | |||
| 5b118fdef4 | |||
| 337c6e91d8 | |||
| b0dc7ea6da | |||
| 67d56ae427 | |||
| 6829c10a10 | |||
| 6a37472023 | |||
| d10fa2bd86 | |||
| e722cf8791 | |||
| bc4205a1d0 | |||
| ea5af417fb | |||
| c70c364754 | |||
| 9cda4563c0 | |||
| fc927e0e25 | |||
| 7915835a93 | |||
| 0c5db90de8 | |||
| 637332de2d | |||
| e77e7c4bba | |||
| 1798d1af6e | |||
| 31cec05712 | |||
| f2de0509f5 | |||
| 26d357e846 | |||
| 4e2f08cc7a | |||
| 91a0f248a1 | |||
| 03462b6e39 | |||
| 37f8ea234f | |||
| 3f920f645c | |||
| a937a06d3e | |||
| dd092dce95 | |||
| dfea7ec939 | |||
| 0e7c027ff1 | |||
| 8b6f77095a | |||
| dbe7d04282 | |||
| fb7964fde7 | |||
| f45b83f0c1 | |||
| f28abe8fde | |||
| 15faaf8bc3 | |||
| a15636f808 | |||
| 5d396c4e3b | |||
| bdccde5c9b | |||
| 7dd01dd54a | |||
| e4b21e6caa | |||
| 2afbffa924 | |||
| 385f83a7de | |||
| 50f5ef2fb6 | |||
| 13f273ad74 | |||
| 09bd8287e7 | |||
| 35313257c5 | |||
| 07bce54ad3 | |||
| 41488252ff | |||
| 8d1f882512 | |||
| dec6b67236 | |||
| 0cf8eadef8 | |||
| 7d16710fb4 | |||
| 9253fccf04 | |||
| eab771cd1a | |||
| 4f6518dad7 | |||
| f8e53e837d | |||
| c5854f19f7 | |||
| 5bb6de80b2 | |||
| c4e31bd968 | |||
| 2887c379de | |||
| ea8fb97beb | |||
| c5bd760133 | |||
| 942642c0f4 | |||
| 78407e19a9 | |||
| 47a4e61b8b | |||
| 5141270346 | |||
| dc7ab2696a | |||
| 14034968df | |||
| aef136934b | |||
| 7d0a38270d | |||
| 07154303ed | |||
| 4f39766211 | |||
| 304b598a05 | |||
| afd080d005 | |||
| 1232cfd194 | |||
| 7e72d8bf66 | |||
| 0d82bbf74f | |||
| aed5a77540 | |||
| f54d597b2e | |||
| 2efb95015b | |||
| f88db0f547 | |||
| 0b7accf86c | |||
| ab82f09e5d | |||
| 0f72d1a388 | |||
| ef3489a23e | |||
| 8bbab627a0 | |||
| 76ff216a5f | |||
| b40ecf04ce | |||
| eeaa095cd3 | |||
| 1985cfc955 | |||
| 517270a943 | |||
| 6a6606cd64 | |||
| 174867295b | |||
| ad5bf04c4e | |||
| 2deacf8eaa | |||
| e133b8b708 | |||
| 52e93150e6 | |||
| a38b24136b | |||
| 78f682590a | |||
| 528ec3cdd8 | |||
| 1986c17052 | |||
| 5ec317a899 | |||
| 9d8987bde8 | |||
| a6d172111b | |||
| 9271f7c48c | |||
| 74e15ea9f5 | |||
| 2c49f9aad3 | |||
| cc933b9cdb | |||
| fdaa8202b9 | |||
| 85d4dc3e20 | |||
| 11a6e42256 | |||
| b1cfa5aef5 | |||
| f2b230a0b8 | |||
| 8aa630ea48 | |||
| ad249c7fac | |||
| fccb395168 | |||
| 8d130123d9 | |||
| d97c4f403c | |||
| e86e716f7a | |||
| 870305aa93 | |||
| b9be543596 | |||
| 43d49f54be | |||
| 753c711cd7 | |||
| 2e9cc6e98a | |||
| 726eea9a97 | |||
| 467b5fc595 | |||
| 995f2b3f76 | |||
| e57ce37ac1 | |||
| a581c0d147 | |||
| 21c2119349 | |||
| f12a951f22 | |||
| d2d4892873 | |||
| 2b449683f3 | |||
| 9d73271db2 | |||
| 7ef80a845d | |||
| 33760e122c | |||
| dd62801b22 | |||
| 5415abf80b | |||
| 6388019ad4 | |||
| 2fe67d3d72 | |||
| 1e32329e61 | |||
| e2a1f08e43 | |||
| 11c89695a1 | |||
| 5f49eb8b24 | |||
| 3cc14c2a6d | |||
| aa30ef827c | |||
| ebe214e8ac | |||
| 8fd41d3b28 | |||
| a7f6ad137a | |||
| 1b763da529 | |||
| b7d6c5d9f7 | |||
| e7d3d515df | |||
| 145733ce77 | |||
| 1a63cbccb2 | |||
| 07ac9eb538 | |||
| 14aa89aac8 | |||
| e66033e53e | |||
| dcb837b531 | |||
| 51d3fb1ebc | |||
| 826b53f691 | |||
| b6605b57e0 | |||
| f03e8e6056 | |||
| a33a9a5b26 | |||
| 67ed7a0edd | |||
| 9b51be4ba6 | |||
| c3d9b42cdf | |||
| b2377d4c0b | |||
| dee58ead7f | |||
| 887985523e | |||
| cabc299447 | |||
| 21adee8f40 | |||
| afaab12b66 | |||
| 93860d0643 | |||
| b43554fbb1 | |||
| 5871fb9ce0 | |||
| f05368ed24 | |||
| 732b91e53d | |||
| d03ecda333 | |||
| 7a722d5060 | |||
| 2795f0ed9d | |||
| 92bc23e484 | |||
| 5a98bd9ee3 | |||
| bfabaf3789 | |||
| cf6c4ab7ec | |||
| 7c27e10226 | |||
| 20ff9ba89b | |||
| 211e2bb8d9 | |||
| cee3efbda8 | |||
| fb48111e46 | |||
| 8c3e72f2c8 | |||
| aa46318425 | |||
| 3d3118f8b0 | |||
| b6f1a2eb55 | |||
| 8eb50186e0 | |||
| 4dec5f4de8 | |||
| 8e0c036158 | |||
| 7d985ff3fd | |||
| d3a2f5e268 | |||
| 59b3961ad4 | |||
| dbc9a60c5f | |||
| ce687431f3 | |||
| 71ccc5753b | |||
| 13886435a6 | |||
| 08e2182042 | |||
| d60595cc27 | |||
| 8c7396c35a | |||
| 42b2fd8eec | |||
| bc946e4fd7 | |||
| c488cec641 | |||
| fcc3c69a49 | |||
| 350c2e835b | |||
| a0a031677e | |||
| cc0d045f5c | |||
| aebe1fddab | |||
| 77ee306b57 | |||
| 6750fdaae1 | |||
| dd6989d551 | |||
| 0c2fed49e2 | |||
| a4ee9bd045 | |||
| 6d9397d573 | |||
| dc9445f873 | |||
| 17bc40ec1c | |||
| 2184fef82f | |||
| 7e1b5c6ce4 | |||
| 36da8a5cee | |||
| fbe85f399d | |||
| 880b27b19e | |||
| cc06f070d1 | |||
| 2f988aa5e6 | |||
| d294a10e83 | |||
| defcbef7ab | |||
| d90eecd4a2 | |||
| 0d6d077e6a | |||
| be09fc9bbb | |||
| fc9d78e26b | |||
| 9f83164c40 | |||
| 857974ab8a | |||
| d70636f4d4 | |||
| 09e467cc4c | |||
| 51ed9c2a40 | |||
| a9a05350a9 | |||
| fe9ea3b4b4 | |||
| f944b453c4 | |||
| a993630cf9 | |||
| abc081ce9c | |||
| 207940046b | |||
| 47efbc6d75 | |||
| 17279e8a4f | |||
| 06c631db05 | |||
| 7952bad41f | |||
| 3308f81c3a | |||
| 75e6da02d3 | |||
| 59ec931d8f | |||
| 4b3c5ea99e | |||
| d4ea4a7eef | |||
| 5fbdadefb2 | |||
| 4da77e4200 | |||
| d797504407 | |||
| 84915268ee | |||
| 3b59d47e07 | |||
| fc94c5399a | |||
| 8e5f472e27 | |||
| 5e7883945b | |||
| a4bd6b9a96 | |||
| 4c253748c2 | |||
| 8f6e1fb5b3 | |||
| 4e665a71bd |
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Problem
|
||||
about: Something does not seem right
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Suggestion
|
||||
about: Share how Serde could support your use case better
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Documentation
|
||||
about: Certainly there is room for improvement
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Help or discussion
|
||||
about: This is the right place
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Anything else!
|
||||
about: Whatever is on your mind
|
||||
|
||||
---
|
||||
|
||||
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
Cargo.lock
|
||||
target
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.sw[po]
|
||||
Cargo.lock
|
||||
|
||||
@@ -5,6 +5,7 @@ cache: cargo
|
||||
# run builds for all the trains (and more)
|
||||
rust:
|
||||
- 1.13.0
|
||||
- 1.15.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
+52
-31
@@ -1,45 +1,66 @@
|
||||
# Contributing to Serde
|
||||
|
||||
Serde welcomes contribution from everyone. Here are the guidelines if you are
|
||||
thinking of helping us:
|
||||
Serde welcomes contribution from everyone in the form of suggestions, bug
|
||||
reports, pull requests, and feedback. This document gives some guidance if you
|
||||
are thinking of helping us.
|
||||
|
||||
## Contributions
|
||||
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.
|
||||
|
||||
Contributions to Serde or its dependencies should be made in the form of GitHub
|
||||
pull requests. Each pull request will be reviewed by a core contributor
|
||||
(someone with permission to land patches) and either landed in the main tree or
|
||||
given feedback for changes that would be required. All contributions should
|
||||
follow this format, even those from core contributors.
|
||||
[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
|
||||
|
||||
Should you wish to work on an issue, please claim it first by commenting on
|
||||
the GitHub issue that you want to work on it. This is to prevent duplicated
|
||||
efforts from contributors on the same issue.
|
||||
## Submitting bug reports and feature requests
|
||||
|
||||
## Pull Request Checklist
|
||||
Serde development is spread across lots of repositories, but this serde-rs/serde
|
||||
repository is always a safe choice for opening any issues related to Serde.
|
||||
|
||||
- Branch from the master branch and, if needed, rebase to the current master
|
||||
branch before submitting your pull request. If it doesn't merge cleanly with
|
||||
master you may be asked to rebase your changes.
|
||||
When reporting a bug or asking for help, please include enough details so that
|
||||
the people helping you can reproduce the behavior you are seeing. For some tips
|
||||
on how to approach this, read about how to produce a [Minimal, Complete, and
|
||||
Verifiable example].
|
||||
|
||||
- Commits should be as small as possible, while ensuring that each commit is
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
[Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve
|
||||
|
||||
- If your patch is not getting reviewed or you need a specific person to review
|
||||
it, you can @-reply a reviewer asking for a review in the pull request or a
|
||||
comment, or you can ask for a review in `#serde` on `irc.mozilla.org`.
|
||||
When making a feature request, please make it clear what problem you intend to
|
||||
solve with the feature, any ideas for how Serde could support solving that
|
||||
problem, any possible alternatives, and any disadvantages.
|
||||
|
||||
- Add tests relevant to the fixed bug or new feature.
|
||||
## Running the test suite
|
||||
|
||||
We encourage you to check that the test suite passes locally before submitting a
|
||||
pull request with your changes. If anything does not pass, typically it will be
|
||||
easier to iterate and fix it locally than waiting for the CI servers to run
|
||||
tests for you.
|
||||
|
||||
##### In the [`serde`] directory
|
||||
|
||||
```sh
|
||||
# Test all the example code in Serde documentation
|
||||
cargo test
|
||||
```
|
||||
|
||||
##### 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
|
||||
|
||||
```sh
|
||||
# Run the full test suite, including tests of unstable functionality
|
||||
cargo test --features unstable
|
||||
```
|
||||
|
||||
[`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
|
||||
|
||||
## Conduct
|
||||
|
||||
In all Serde-related forums, we follow the [Rust Code of
|
||||
Conduct](https://www.rust-lang.org/conduct.html). For escalation or moderation
|
||||
issues, please contact Erick (erick.tryzelaar@gmail.com) instead of the Rust
|
||||
moderation team.
|
||||
In all Serde-related forums, we follow the [Rust Code of Conduct]. For
|
||||
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
||||
instead of the Rust moderation team.
|
||||
|
||||
## Communication
|
||||
|
||||
Beyond opening tickets on the
|
||||
[serde-rs/serde](https://github.com/serde-rs/serde) project, Serde contributors
|
||||
frequent the `#serde` channel on
|
||||
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC).
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html
|
||||
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"serde",
|
||||
"serde_codegen_internals",
|
||||
"serde_derive",
|
||||
"serde_derive_internals",
|
||||
"serde_test",
|
||||
"test_suite",
|
||||
"test_suite/no_std",
|
||||
]
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
# Serde   [](https://travis-ci.org/serde-rs/serde) [](https://crates.io/crates/serde)
|
||||
# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc]
|
||||
|
||||
[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master
|
||||
[travis]: https://travis-ci.org/serde-rs/serde
|
||||
[Latest Version]: https://img.shields.io/crates/v/serde.svg
|
||||
[crates.io]: https://crates.io/crates/serde
|
||||
[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg
|
||||
[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html
|
||||
|
||||
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
|
||||
|
||||
@@ -15,10 +22,36 @@ You may be looking for:
|
||||
|
||||
## Serde in action
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Click to show Cargo.toml.
|
||||
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
||||
</summary>
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
|
||||
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||
# required when using Serde.
|
||||
serde = "1.0"
|
||||
|
||||
# Support for #[derive(Serialize, Deserialize)]. Required if you want Serde
|
||||
# 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
|
||||
# but you may be using a different one.
|
||||
serde_json = "1.0"
|
||||
```
|
||||
|
||||
</details>
|
||||
<p></p>
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
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
|
||||
|
||||
test_script:
|
||||
- sh -c 'PATH=`rustc --print sysroot`/bin:$PATH ./travis.sh'
|
||||
@@ -0,0 +1 @@
|
||||
error_on_line_overflow = false
|
||||
+44
-14
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.9.8"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
version = "1.0.60" # remember to update html_root_url
|
||||
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"
|
||||
@@ -9,26 +9,56 @@ repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://docs.serde.rs/serde/"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
categories = ["encoding"]
|
||||
readme = "../README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "build.rs", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
build = "build.rs"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
appveyor = { repository = "serde-rs/serde" }
|
||||
|
||||
[dependencies]
|
||||
serde_derive = { version = "1.0", optional = true, path = "../serde_derive" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
|
||||
### FEATURES #################################################################
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
# Re-export the derive(Serialize, Deserialize) macros. This is specifically
|
||||
# intended for library crates that provide optional Serde impls behind a Cargo
|
||||
# cfg of their own. All other crates should depend on serde_derive directly.
|
||||
#
|
||||
# Please refer to the long comment above the line `pub use serde_derive::*` in
|
||||
# src/lib.rs before enabling this feature. If you think you need this feature
|
||||
# and your use case does not precisely match the one described in the comment,
|
||||
# please open an issue to let us know about your use case.
|
||||
derive = ["serde_derive"]
|
||||
|
||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||
# Requires a dependency on the Rust standard library.
|
||||
std = []
|
||||
|
||||
# Provide impls for types that require unstable functionality. For tracking and
|
||||
# discussion of unstable functionality please refer to this issue:
|
||||
#
|
||||
# https://github.com/serde-rs/serde/issues/812
|
||||
unstable = []
|
||||
|
||||
# Provide impls for types in the Rust core allocation and collections library
|
||||
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
|
||||
# be enabled without depending on all of std.
|
||||
#
|
||||
# Requires a dependency on the unstable core allocation library:
|
||||
#
|
||||
# https://doc.rust-lang.org/alloc/
|
||||
alloc = ["unstable"]
|
||||
collections = ["alloc"]
|
||||
unstable-testing = ["unstable", "std"]
|
||||
|
||||
# to get serde_derive picked up by play.integer32.com
|
||||
playground = ["serde_derive"]
|
||||
|
||||
[dependencies]
|
||||
serde_derive = { version = "0.9", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = "0.9"
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
rc = []
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str::{self, FromStr};
|
||||
|
||||
fn main() {
|
||||
let rustc = match env::var_os("RUSTC") {
|
||||
Some(rustc) => rustc,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let output = match Command::new(rustc).arg("--version").output() {
|
||||
Ok(output) => output,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let version = match str::from_utf8(&output.stdout) {
|
||||
Ok(version) => version,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return;
|
||||
}
|
||||
|
||||
let next = match pieces.next() {
|
||||
Some(next) => next,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let minor = match u32::from_str(next) {
|
||||
Ok(minor) => minor,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// 128-bit integers stabilized in Rust 1.26:
|
||||
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
|
||||
if minor >= 26 {
|
||||
println!("cargo:rustc-cfg=integer128");
|
||||
}
|
||||
|
||||
// Non-zero integers stabilized in Rust 1.28:
|
||||
// https://github.com/rust-lang/rust/pull/50808
|
||||
if minor >= 28 {
|
||||
println!("cargo:rustc-cfg=num_nonzero");
|
||||
}
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
|
||||
//!
|
||||
//! Without specialization, Rust forces us to treat `&[u8]` just like any other
|
||||
//! slice and `Vec<u8>` just like any other vector. In reality this particular
|
||||
//! slice and vector can often be serialized and deserialized in a more
|
||||
//! efficient, compact representation in many formats.
|
||||
//!
|
||||
//! When working with such a format, you can opt into specialized handling of
|
||||
//! `&[u8]` by wrapping it in `bytes::Bytes` and `Vec<u8>` by wrapping it in
|
||||
//! `bytes::ByteBuf`.
|
||||
//!
|
||||
//! Rust support for specialization is being tracked in
|
||||
//! [rust-lang/rust#31844][specialization]. Once it lands in the stable compiler
|
||||
//! we will be deprecating these wrapper types in favor of optimizing `&[u8]`
|
||||
//! and `Vec<u8>` out of the box.
|
||||
//!
|
||||
//! [specialization]: https://github.com/rust-lang/rust/issues/31844
|
||||
|
||||
use core::{ops, fmt, char, iter, slice};
|
||||
use core::fmt::Write;
|
||||
|
||||
use ser;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub use self::bytebuf::ByteBuf;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[doc(hidden)] // does anybody need this?
|
||||
pub use self::bytebuf::ByteBufVisitor;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::Vec;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Wraps a `&[u8]` in order to serialize in an efficient way. Does not support
|
||||
/// deserialization.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde_derive;
|
||||
/// # extern crate serde;
|
||||
/// # use std::net::IpAddr;
|
||||
/// #
|
||||
/// use serde::bytes::Bytes;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// #[derive(Serialize)]
|
||||
/// struct Packet<'a> {
|
||||
/// destination: IpAddr,
|
||||
/// payload: Bytes<'a>,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Bytes<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Bytes<'a> {
|
||||
/// Wrap an existing `&[u8]`.
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Bytes { bytes: bytes }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str("b\""));
|
||||
for c in escape_bytestring(self.bytes) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for Bytes<'a> {
|
||||
fn from(bytes: &'a [u8]) -> Self {
|
||||
Bytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
|
||||
fn from(bytes: &'a Vec<u8>) -> Self {
|
||||
Bytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<&'a [u8]> for Bytes<'a> {
|
||||
fn into(self) -> &'a [u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Deref for Bytes<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::Serialize for Bytes<'a> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
mod bytebuf {
|
||||
use core::cmp;
|
||||
use core::ops;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
|
||||
use ser;
|
||||
use de;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::{String, Vec};
|
||||
|
||||
/// Wraps a `Vec<u8>` in order to serialize and deserialize in an efficient
|
||||
/// way.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde_derive;
|
||||
/// # extern crate serde;
|
||||
/// # use std::net::IpAddr;
|
||||
/// #
|
||||
/// use serde::bytes::ByteBuf;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Packet {
|
||||
/// destination: IpAddr,
|
||||
/// payload: ByteBuf,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf::from(Vec::new())
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf::from(Vec::with_capacity(cap))
|
||||
}
|
||||
|
||||
/// Wrap existing bytes in a `ByteBuf`.
|
||||
pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
|
||||
ByteBuf { bytes: bytes.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ByteBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str("b\""));
|
||||
for c in super::escape_bytestring(self.bytes.as_ref()) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for ByteBuf {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ByteBuf {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
ByteBuf::from(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Vec<u8>> for ByteBuf {
|
||||
fn as_ref(&self) -> &Vec<u8> {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ByteBuf {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Vec<u8>> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ByteBuf {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DerefMut for ByteBuf {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Serialize for ByteBuf {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This type implements the `serde::de::Visitor` trait for a `ByteBuf`.
|
||||
pub struct ByteBufVisitor;
|
||||
|
||||
impl de::Visitor for ByteBufVisitor {
|
||||
type Value = ByteBuf;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::new())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
|
||||
where V: de::SeqVisitor
|
||||
{
|
||||
let len = cmp::min(visitor.size_hint().0, 4096);
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
while let Some(value) = try!(visitor.visit()) {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(ByteBuf::from(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Deserialize for ByteBuf {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
|
||||
where D: de::Deserializer
|
||||
{
|
||||
deserializer.deserialize_byte_buf(ByteBufVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[inline]
|
||||
fn escape_bytestring<'a>
|
||||
(bytes: &'a [u8])
|
||||
-> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
|
||||
fn f(b: &u8) -> char::EscapeDefault {
|
||||
char::from_u32(*b as u32).unwrap().escape_default()
|
||||
}
|
||||
bytes.iter().flat_map(f as fn(&u8) -> char::EscapeDefault)
|
||||
}
|
||||
@@ -1,797 +0,0 @@
|
||||
// This module is doc(hidden) and nothing here should be used outside of
|
||||
// generated code.
|
||||
//
|
||||
// We will iterate on the implementation for a few releases and only have to
|
||||
// worry about backward compatibility for the `untagged` and `tag` attributes
|
||||
// rather than for this entire mechanism.
|
||||
//
|
||||
// This issue is tracking making some of this stuff public:
|
||||
// https://github.com/serde-rs/serde/issues/741
|
||||
|
||||
#![doc(hidden)]
|
||||
|
||||
use core::cmp;
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "collections"))]
|
||||
use collections::{String, Vec};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqVisitor, MapVisitor,
|
||||
EnumVisitor, Unexpected};
|
||||
|
||||
/// Used from generated code to buffer the contents of the Deserializer when
|
||||
/// deserializing untagged enums and internally tagged enums.
|
||||
///
|
||||
/// Not public API. Use serde-value instead.
|
||||
#[derive(Debug)]
|
||||
pub enum Content {
|
||||
// Don't mind the PhantomData, just need to use E somewhere.
|
||||
Bool(bool),
|
||||
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
|
||||
Char(char),
|
||||
String(String),
|
||||
Bytes(Vec<u8>),
|
||||
|
||||
None,
|
||||
Some(Box<Content>),
|
||||
|
||||
Unit,
|
||||
Newtype(Box<Content>),
|
||||
Seq(Vec<Content>),
|
||||
Map(Vec<(Content, Content)>),
|
||||
}
|
||||
|
||||
impl Deserialize for Content {
|
||||
fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> {
|
||||
// Untagged and internally tagged enums are only supported in
|
||||
// self-describing formats.
|
||||
deserializer.deserialize(ContentVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentVisitor;
|
||||
|
||||
impl Visitor for ContentVisitor {
|
||||
type Value = Content;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str("any value")
|
||||
}
|
||||
|
||||
fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::Bool(value))
|
||||
}
|
||||
|
||||
fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::I8(value))
|
||||
}
|
||||
|
||||
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::I16(value))
|
||||
}
|
||||
|
||||
fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::I32(value))
|
||||
}
|
||||
|
||||
fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::I64(value))
|
||||
}
|
||||
|
||||
fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::U8(value))
|
||||
}
|
||||
|
||||
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::U16(value))
|
||||
}
|
||||
|
||||
fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::U32(value))
|
||||
}
|
||||
|
||||
fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::U64(value))
|
||||
}
|
||||
|
||||
fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::F32(value))
|
||||
}
|
||||
|
||||
fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::F64(value))
|
||||
}
|
||||
|
||||
fn visit_char<F>(self, value: char) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::Char(value))
|
||||
}
|
||||
|
||||
fn visit_str<F>(self, value: &str) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::String(value.into()))
|
||||
}
|
||||
|
||||
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::String(value))
|
||||
}
|
||||
|
||||
fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::Bytes(value.into()))
|
||||
}
|
||||
|
||||
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::Bytes(value))
|
||||
}
|
||||
|
||||
fn visit_unit<F>(self) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::Unit)
|
||||
}
|
||||
|
||||
fn visit_none<F>(self) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
Ok(Content::None)
|
||||
}
|
||||
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
Deserialize::deserialize(deserializer).map(|v| Content::Some(Box::new(v)))
|
||||
}
|
||||
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
Deserialize::deserialize(deserializer).map(|v| Content::Newtype(Box::new(v)))
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: SeqVisitor
|
||||
{
|
||||
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
|
||||
while let Some(e) = try!(visitor.visit()) {
|
||||
vec.push(e);
|
||||
}
|
||||
Ok(Content::Seq(vec))
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: MapVisitor
|
||||
{
|
||||
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
|
||||
while let Some(kv) = try!(visitor.visit()) {
|
||||
vec.push(kv);
|
||||
}
|
||||
Ok(Content::Map(vec))
|
||||
}
|
||||
|
||||
fn visit_enum<V>(self, _visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: EnumVisitor
|
||||
{
|
||||
Err(de::Error::custom("untagged and internally tagged enums do not support enum input"))
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the type of the map keys in an internally tagged enum.
|
||||
///
|
||||
/// Not public API.
|
||||
pub enum TagOrContent {
|
||||
Tag,
|
||||
Content(Content),
|
||||
}
|
||||
|
||||
struct TagOrContentVisitor {
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
impl TagOrContentVisitor {
|
||||
fn new(name: &'static str) -> Self {
|
||||
TagOrContentVisitor { name: name }
|
||||
}
|
||||
}
|
||||
|
||||
impl DeserializeSeed for TagOrContentVisitor {
|
||||
type Value = TagOrContent;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
// Internally tagged enums are only supported in self-describing
|
||||
// formats.
|
||||
deserializer.deserialize(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor for TagOrContentVisitor {
|
||||
type Value = TagOrContent;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "a type tag `{}` or any other value", self.name)
|
||||
}
|
||||
|
||||
fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_bool(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_i8(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_i16(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_i32(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_i64(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_u8(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_u16(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_u32(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_u64(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_f32(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_f64(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_char<F>(self, value: char) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_char(value).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_str<F>(self, value: &str) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
if value == self.name {
|
||||
Ok(TagOrContent::Tag)
|
||||
} else {
|
||||
ContentVisitor.visit_str(value).map(TagOrContent::Content)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<F>(self, value: String) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
if value == self.name {
|
||||
Ok(TagOrContent::Tag)
|
||||
} else {
|
||||
ContentVisitor.visit_string(value).map(TagOrContent::Content)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
if value == self.name.as_bytes() {
|
||||
Ok(TagOrContent::Tag)
|
||||
} else {
|
||||
ContentVisitor.visit_bytes(value).map(TagOrContent::Content)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
if value == self.name.as_bytes() {
|
||||
Ok(TagOrContent::Tag)
|
||||
} else {
|
||||
ContentVisitor.visit_byte_buf(value).map(TagOrContent::Content)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_unit<F>(self) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_unit().map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_none<F>(self) -> Result<Self::Value, F>
|
||||
where F: de::Error
|
||||
{
|
||||
ContentVisitor.visit_none().map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
ContentVisitor.visit_some(deserializer).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
ContentVisitor.visit_newtype_struct(deserializer).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: SeqVisitor
|
||||
{
|
||||
ContentVisitor.visit_seq(visitor).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: MapVisitor
|
||||
{
|
||||
ContentVisitor.visit_map(visitor).map(TagOrContent::Content)
|
||||
}
|
||||
|
||||
fn visit_enum<V>(self, visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: EnumVisitor
|
||||
{
|
||||
ContentVisitor.visit_enum(visitor).map(TagOrContent::Content)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by generated code to deserialize an internally tagged enum.
|
||||
///
|
||||
/// Not public API.
|
||||
pub struct TaggedContent<T> {
|
||||
pub tag: T,
|
||||
pub content: Content,
|
||||
}
|
||||
|
||||
/// Not public API.
|
||||
pub struct TaggedContentVisitor<T> {
|
||||
tag_name: &'static str,
|
||||
tag: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> TaggedContentVisitor<T> {
|
||||
/// Visitor for the content of an internally tagged enum with the given tag
|
||||
/// name.
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
TaggedContentVisitor {
|
||||
tag_name: name,
|
||||
tag: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DeserializeSeed for TaggedContentVisitor<T>
|
||||
where T: Deserialize
|
||||
{
|
||||
type Value = TaggedContent<T>;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
// Internally tagged enums are only supported in self-describing
|
||||
// formats.
|
||||
deserializer.deserialize(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Visitor for TaggedContentVisitor<T>
|
||||
where T: Deserialize
|
||||
{
|
||||
type Value = TaggedContent<T>;
|
||||
|
||||
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str("any value")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
where V: MapVisitor
|
||||
{
|
||||
let mut tag = None;
|
||||
let mut vec = Vec::with_capacity(cmp::min(visitor.size_hint().0, 4096));
|
||||
while let Some(k) = try!(visitor.visit_key_seed(TagOrContentVisitor::new(self.tag_name))) {
|
||||
match k {
|
||||
TagOrContent::Tag => {
|
||||
if tag.is_some() {
|
||||
return Err(de::Error::duplicate_field(self.tag_name));
|
||||
}
|
||||
tag = Some(try!(visitor.visit_value()));
|
||||
}
|
||||
TagOrContent::Content(k) => {
|
||||
let v = try!(visitor.visit_value());
|
||||
vec.push((k, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
match tag {
|
||||
None => Err(de::Error::missing_field(self.tag_name)),
|
||||
Some(tag) => {
|
||||
Ok(TaggedContent {
|
||||
tag: tag,
|
||||
content: Content::Map(vec),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by generated code to deserialize an adjacently tagged enum.
|
||||
///
|
||||
/// Not public API.
|
||||
pub enum TagOrContentField {
|
||||
Tag,
|
||||
Content,
|
||||
}
|
||||
|
||||
/// Not public API.
|
||||
pub struct TagOrContentFieldVisitor {
|
||||
pub tag: &'static str,
|
||||
pub content: &'static str,
|
||||
}
|
||||
|
||||
impl DeserializeSeed for TagOrContentFieldVisitor {
|
||||
type Value = TagOrContentField;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
deserializer.deserialize_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor for TagOrContentFieldVisitor {
|
||||
type Value = TagOrContentField;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{:?} or {:?}", self.tag, self.content)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, field: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
{
|
||||
if field == self.tag {
|
||||
Ok(TagOrContentField::Tag)
|
||||
} else if field == self.content {
|
||||
Ok(TagOrContentField::Content)
|
||||
} else {
|
||||
Err(de::Error::invalid_value(Unexpected::Str(field), &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Not public API
|
||||
pub struct ContentDeserializer<E> {
|
||||
content: Content,
|
||||
err: PhantomData<E>,
|
||||
}
|
||||
|
||||
/// Used when deserializing an internally tagged enum because the content will
|
||||
/// be used exactly once.
|
||||
impl<E> Deserializer for ContentDeserializer<E>
|
||||
where E: de::Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
match self.content {
|
||||
Content::Bool(v) => visitor.visit_bool(v),
|
||||
Content::U8(v) => visitor.visit_u8(v),
|
||||
Content::U16(v) => visitor.visit_u16(v),
|
||||
Content::U32(v) => visitor.visit_u32(v),
|
||||
Content::U64(v) => visitor.visit_u64(v),
|
||||
Content::I8(v) => visitor.visit_i8(v),
|
||||
Content::I16(v) => visitor.visit_i16(v),
|
||||
Content::I32(v) => visitor.visit_i32(v),
|
||||
Content::I64(v) => visitor.visit_i64(v),
|
||||
Content::F32(v) => visitor.visit_f32(v),
|
||||
Content::F64(v) => visitor.visit_f64(v),
|
||||
Content::Char(v) => visitor.visit_char(v),
|
||||
Content::String(v) => visitor.visit_string(v),
|
||||
Content::Unit => visitor.visit_unit(),
|
||||
Content::None => visitor.visit_none(),
|
||||
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
|
||||
Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)),
|
||||
Content::Seq(v) => {
|
||||
let seq = v.into_iter().map(ContentDeserializer::new);
|
||||
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
|
||||
let value = try!(visitor.visit_seq(&mut seq_visitor));
|
||||
try!(seq_visitor.end());
|
||||
Ok(value)
|
||||
}
|
||||
Content::Map(v) => {
|
||||
let map = v.into_iter()
|
||||
.map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v)));
|
||||
let mut map_visitor = de::value::MapDeserializer::new(map);
|
||||
let value = try!(visitor.visit_map(&mut map_visitor));
|
||||
try!(map_visitor.end());
|
||||
Ok(value)
|
||||
}
|
||||
Content::Bytes(v) => visitor.visit_byte_buf(v),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
match self.content {
|
||||
Content::None => visitor.visit_none(),
|
||||
Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)),
|
||||
Content::Unit => visitor.visit_unit(),
|
||||
_ => visitor.visit_some(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
forward_to_deserialize! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
|
||||
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
|
||||
struct_field tuple enum ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> ContentDeserializer<E> {
|
||||
/// private API, don't use
|
||||
pub fn new(content: Content) -> Self {
|
||||
ContentDeserializer {
|
||||
content: content,
|
||||
err: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Not public API.
|
||||
pub struct ContentRefDeserializer<'a, E> {
|
||||
content: &'a Content,
|
||||
err: PhantomData<E>,
|
||||
}
|
||||
|
||||
/// Used when deserializing an untagged enum because the content may need to be
|
||||
/// used more than once.
|
||||
impl<'a, E> Deserializer for ContentRefDeserializer<'a, E>
|
||||
where E: de::Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
match *self.content {
|
||||
Content::Bool(v) => visitor.visit_bool(v),
|
||||
Content::U8(v) => visitor.visit_u8(v),
|
||||
Content::U16(v) => visitor.visit_u16(v),
|
||||
Content::U32(v) => visitor.visit_u32(v),
|
||||
Content::U64(v) => visitor.visit_u64(v),
|
||||
Content::I8(v) => visitor.visit_i8(v),
|
||||
Content::I16(v) => visitor.visit_i16(v),
|
||||
Content::I32(v) => visitor.visit_i32(v),
|
||||
Content::I64(v) => visitor.visit_i64(v),
|
||||
Content::F32(v) => visitor.visit_f32(v),
|
||||
Content::F64(v) => visitor.visit_f64(v),
|
||||
Content::Char(v) => visitor.visit_char(v),
|
||||
Content::String(ref v) => visitor.visit_str(v),
|
||||
Content::Unit => visitor.visit_unit(),
|
||||
Content::None => visitor.visit_none(),
|
||||
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
|
||||
Content::Newtype(ref v) => visitor.visit_newtype_struct(ContentRefDeserializer::new(v)),
|
||||
Content::Seq(ref v) => {
|
||||
let seq = v.into_iter().map(ContentRefDeserializer::new);
|
||||
let mut seq_visitor = de::value::SeqDeserializer::new(seq);
|
||||
let value = try!(visitor.visit_seq(&mut seq_visitor));
|
||||
try!(seq_visitor.end());
|
||||
Ok(value)
|
||||
}
|
||||
Content::Map(ref v) => {
|
||||
let map = v.into_iter().map(|&(ref k, ref v)| {
|
||||
(ContentRefDeserializer::new(k), ContentRefDeserializer::new(v))
|
||||
});
|
||||
let mut map_visitor = de::value::MapDeserializer::new(map);
|
||||
let value = try!(visitor.visit_map(&mut map_visitor));
|
||||
try!(map_visitor.end());
|
||||
Ok(value)
|
||||
}
|
||||
Content::Bytes(ref v) => visitor.visit_bytes(v),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
match *self.content {
|
||||
Content::None => visitor.visit_none(),
|
||||
Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)),
|
||||
Content::Unit => visitor.visit_unit(),
|
||||
_ => visitor.visit_some(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where V: Visitor
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
forward_to_deserialize! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
|
||||
seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
|
||||
struct_field tuple enum ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> ContentRefDeserializer<'a, E> {
|
||||
/// private API, don't use
|
||||
pub fn new(content: &'a Content) -> Self {
|
||||
ContentRefDeserializer {
|
||||
content: content,
|
||||
err: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> de::value::ValueDeserializer<E> for ContentDeserializer<E>
|
||||
where E: de::Error
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> de::value::ValueDeserializer<E> for ContentRefDeserializer<'a, E>
|
||||
where E: de::Error
|
||||
{
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor for deserializing an internally tagged unit variant.
|
||||
///
|
||||
/// Not public API.
|
||||
pub struct InternallyTaggedUnitVisitor<'a> {
|
||||
type_name: &'a str,
|
||||
variant_name: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> InternallyTaggedUnitVisitor<'a> {
|
||||
/// Not public API.
|
||||
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
|
||||
InternallyTaggedUnitVisitor {
|
||||
type_name: type_name,
|
||||
variant_name: variant_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor for InternallyTaggedUnitVisitor<'a> {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
|
||||
where V: MapVisitor
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Visitor for deserializing an untagged unit variant.
|
||||
///
|
||||
/// Not public API.
|
||||
pub struct UntaggedUnitVisitor<'a> {
|
||||
type_name: &'a str,
|
||||
variant_name: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> UntaggedUnitVisitor<'a> {
|
||||
/// Not public API.
|
||||
pub fn new(type_name: &'a str, variant_name: &'a str) -> Self {
|
||||
UntaggedUnitVisitor {
|
||||
type_name: type_name,
|
||||
variant_name: variant_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor for UntaggedUnitVisitor<'a> {
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
|
||||
}
|
||||
|
||||
fn visit_unit<E>(self) -> Result<(), E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+244
-385
@@ -1,6 +1,4 @@
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
@@ -8,402 +6,263 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Extracted from https://github.com/rust-num/num.
|
||||
use lib::*;
|
||||
|
||||
// Rust 1.5 is unhappy that this private module is undocumented.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use core::{usize, u8, u16, u32, u64};
|
||||
use core::{isize, i8, i16, i32, i64};
|
||||
use core::{f32, f64};
|
||||
use core::mem::size_of;
|
||||
|
||||
/// Numbers which have upper and lower bounds
|
||||
pub trait Bounded {
|
||||
// FIXME (#5527): These should be associated constants
|
||||
/// returns the smallest finite number this type can represent
|
||||
fn min_value() -> Self;
|
||||
/// returns the largest finite number this type can represent
|
||||
fn max_value() -> Self;
|
||||
}
|
||||
|
||||
macro_rules! bounded_impl {
|
||||
($t:ty, $min:expr, $max:expr) => {
|
||||
impl Bounded for $t {
|
||||
#[inline]
|
||||
fn min_value() -> $t { $min }
|
||||
|
||||
#[inline]
|
||||
fn max_value() -> $t { $max }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bounded_impl!(usize, usize::MIN, usize::MAX);
|
||||
bounded_impl!(u8, u8::MIN, u8::MAX);
|
||||
bounded_impl!(u16, u16::MIN, u16::MAX);
|
||||
bounded_impl!(u32, u32::MIN, u32::MAX);
|
||||
bounded_impl!(u64, u64::MIN, u64::MAX);
|
||||
|
||||
bounded_impl!(isize, isize::MIN, isize::MAX);
|
||||
bounded_impl!(i8, i8::MIN, i8::MAX);
|
||||
bounded_impl!(i16, i16::MIN, i16::MAX);
|
||||
bounded_impl!(i32, i32::MIN, i32::MAX);
|
||||
bounded_impl!(i64, i64::MIN, i64::MAX);
|
||||
|
||||
bounded_impl!(f32, f32::MIN, f32::MAX);
|
||||
bounded_impl!(f64, f64::MIN, f64::MAX);
|
||||
|
||||
/// A generic trait for converting a value to a number.
|
||||
pub trait ToPrimitive {
|
||||
/// Converts the value of `self` to an `isize`.
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> {
|
||||
self.to_i64().and_then(|x| x.to_isize())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i8`.
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> {
|
||||
self.to_i64().and_then(|x| x.to_i8())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i16`.
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> {
|
||||
self.to_i64().and_then(|x| x.to_i16())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i32`.
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> {
|
||||
self.to_i64().and_then(|x| x.to_i32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i64`.
|
||||
fn to_i64(&self) -> Option<i64>;
|
||||
|
||||
/// Converts the value of `self` to a `usize`.
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
self.to_u64().and_then(|x| x.to_usize())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u8`.
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> {
|
||||
self.to_u64().and_then(|x| x.to_u8())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u16`.
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> {
|
||||
self.to_u64().and_then(|x| x.to_u16())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u32`.
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> {
|
||||
self.to_u64().and_then(|x| x.to_u32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u64`.
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64>;
|
||||
|
||||
/// Converts the value of `self` to an `f32`.
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> {
|
||||
self.to_f64().and_then(|x| x.to_f32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `f64`.
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> {
|
||||
self.to_i64().and_then(|x| x.to_f64())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int_to_int {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let n = $slf as i64;
|
||||
let min_value: $DstT = Bounded::min_value();
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if min_value as i64 <= n && n <= max_value as i64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int_to_uint {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
let zero: $SrcT = 0;
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if zero <= $slf && $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int {
|
||||
($T:ty) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { impl_to_primitive_int_to_int!($T, isize, *self) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { impl_to_primitive_int_to_int!($T, i8, *self) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { impl_to_primitive_int_to_int!($T, i16, *self) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { impl_to_primitive_int_to_int!($T, i32, *self) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { impl_to_primitive_int_to_int!($T, i64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> { impl_to_primitive_int_to_uint!($T, usize, *self) }
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { impl_to_primitive_int_to_uint!($T, u8, *self) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { impl_to_primitive_int_to_uint!($T, u16, *self) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { impl_to_primitive_int_to_uint!($T, u32, *self) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { impl_to_primitive_int_to_uint!($T, u64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { Some(*self as f64) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_to_primitive_int! { isize }
|
||||
impl_to_primitive_int! { i8 }
|
||||
impl_to_primitive_int! { i16 }
|
||||
impl_to_primitive_int! { i32 }
|
||||
impl_to_primitive_int! { i64 }
|
||||
|
||||
macro_rules! impl_to_primitive_uint_to_int {
|
||||
($DstT:ty, $slf:expr) => (
|
||||
{
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_uint_to_uint {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let zero: $SrcT = 0;
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if zero <= $slf && $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_uint {
|
||||
($T:ty) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { impl_to_primitive_uint_to_int!(isize, *self) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { impl_to_primitive_uint_to_int!(i8, *self) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { impl_to_primitive_uint_to_int!(i16, *self) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { impl_to_primitive_uint_to_int!(i32, *self) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { impl_to_primitive_uint_to_int!(i64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
impl_to_primitive_uint_to_uint!($T, usize, *self)
|
||||
}
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { impl_to_primitive_uint_to_uint!($T, u8, *self) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { impl_to_primitive_uint_to_uint!($T, u16, *self) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { impl_to_primitive_uint_to_uint!($T, u32, *self) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { impl_to_primitive_uint_to_uint!($T, u64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { Some(*self as f64) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_to_primitive_uint! { usize }
|
||||
impl_to_primitive_uint! { u8 }
|
||||
impl_to_primitive_uint! { u16 }
|
||||
impl_to_primitive_uint! { u32 }
|
||||
impl_to_primitive_uint! { u64 }
|
||||
|
||||
macro_rules! impl_to_primitive_float_to_float {
|
||||
($SrcT:ident, $DstT:ident, $slf:expr) => (
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
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 {
|
||||
let n = $slf as f64;
|
||||
let max_value: $SrcT = ::core::$SrcT::MAX;
|
||||
if -max_value as f64 <= n && n <= max_value as f64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_float {
|
||||
($T:ident) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { Some(*self as isize) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { Some(*self as i8) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { Some(*self as i16) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { Some(*self as i32) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { Some(*self as i64) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> { Some(*self as usize) }
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { Some(*self as u8) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { Some(*self as u16) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { Some(*self as u32) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { Some(*self as u64) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { impl_to_primitive_float_to_float!($T, f32, *self) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { impl_to_primitive_float_to_float!($T, f64, *self) }
|
||||
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
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl_to_primitive_float! { f32 }
|
||||
impl_to_primitive_float! { f64 }
|
||||
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 {
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
#[inline]
|
||||
fn from_f32(n: f32) -> Option<Self> {
|
||||
FromPrimitive::from_f64(n as f64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_f64(n: f64) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_primitive {
|
||||
($T:ty, $to_ty:ident) => (
|
||||
impl FromPrimitive for $T {
|
||||
#[inline] fn from_i8(n: i8) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i16(n: i16) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i32(n: i32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i64(n: i64) -> Option<$T> { n.$to_ty() }
|
||||
|
||||
#[inline] fn from_u8(n: u8) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u16(n: u16) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u32(n: u32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u64(n: u64) -> Option<$T> { n.$to_ty() }
|
||||
|
||||
#[inline] fn from_f32(n: f32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_f64(n: f64) -> Option<$T> { n.$to_ty() }
|
||||
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)
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_primitive! { isize, to_isize }
|
||||
impl_from_primitive! { i8, to_i8 }
|
||||
impl_from_primitive! { i16, to_i16 }
|
||||
impl_from_primitive! { i32, to_i32 }
|
||||
impl_from_primitive! { i64, to_i64 }
|
||||
impl_from_primitive! { usize, to_usize }
|
||||
impl_from_primitive! { u8, to_u8 }
|
||||
impl_from_primitive! { u16, to_u16 }
|
||||
impl_from_primitive! { u32, to_u32 }
|
||||
impl_from_primitive! { u64, to_u64 }
|
||||
impl_from_primitive! { f32, to_f32 }
|
||||
impl_from_primitive! { f64, to_f64 }
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use lib::*;
|
||||
|
||||
use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
||||
|
||||
/// An efficient way of discarding data from a deserializer.
|
||||
///
|
||||
/// Think of this like `serde_json::Value` in that it can be deserialized from
|
||||
/// any type, except that it does not store any information about the data that
|
||||
/// gets deserialized.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::fmt;
|
||||
/// use std::marker::PhantomData;
|
||||
///
|
||||
/// use serde::de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess, IgnoredAny};
|
||||
///
|
||||
/// /// 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`.
|
||||
/// ///
|
||||
/// /// For example to deserialize only the element at index 3:
|
||||
/// ///
|
||||
/// /// ```rust
|
||||
/// /// NthElement::new(3).deserialize(deserializer)
|
||||
/// /// ```
|
||||
/// pub struct NthElement<T> {
|
||||
/// n: usize,
|
||||
/// marker: PhantomData<T>,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> NthElement<T> {
|
||||
/// pub fn new(n: usize) -> Self {
|
||||
/// NthElement {
|
||||
/// n: n,
|
||||
/// marker: PhantomData,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> Visitor<'de> for NthElement<T>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = T;
|
||||
///
|
||||
/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// write!(formatter, "a sequence in which we care about element {}", self.n)
|
||||
/// }
|
||||
///
|
||||
/// fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
/// where
|
||||
/// A: SeqAccess<'de>,
|
||||
/// {
|
||||
/// // Skip over the first `n` elements.
|
||||
/// for i in 0..self.n {
|
||||
/// // It is an error if the sequence ends before we get to element `n`.
|
||||
/// if seq.next_element::<IgnoredAny>()?.is_none() {
|
||||
/// return Err(de::Error::invalid_length(i, &self));
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Deserialize the one we care about.
|
||||
/// let nth = match seq.next_element()? {
|
||||
/// Some(nth) => nth,
|
||||
/// None => {
|
||||
/// return Err(de::Error::invalid_length(self.n, &self));
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // Skip over any remaining elements in the sequence after `n`.
|
||||
/// while let Some(IgnoredAny) = seq.next_element()? {
|
||||
/// // ignore
|
||||
/// }
|
||||
///
|
||||
/// Ok(nth)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> DeserializeSeed<'de> for NthElement<T>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = T;
|
||||
///
|
||||
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// deserializer.deserialize_seq(self)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
/// # where
|
||||
/// # D: Deserializer<'de>,
|
||||
/// # {
|
||||
/// // Deserialize only the sequence element at index 3 from this deserializer.
|
||||
/// // The element at index 3 is required to be a string. Elements before and
|
||||
/// // after index 3 are allowed to be of any type.
|
||||
/// let s: String = NthElement::new(3).deserialize(deserializer)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct IgnoredAny;
|
||||
|
||||
impl<'de> Visitor<'de> for IgnoredAny {
|
||||
type Value = IgnoredAny;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("anything at all")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bool<E>(self, x: bool) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i64<E>(self, x: i64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = s;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none<E>(self) -> Result<Self::Value, E> {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
IgnoredAny::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
IgnoredAny::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E> {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(IgnoredAny) = try!(seq.next_element()) {
|
||||
// Gobble
|
||||
}
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
while let Some((IgnoredAny, IgnoredAny)) = try!(map.next_entry()) {
|
||||
// Gobble
|
||||
}
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = bytes;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for IgnoredAny {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<IgnoredAny, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_ignored_any(IgnoredAny)
|
||||
}
|
||||
}
|
||||
+1632
-686
File diff suppressed because it is too large
Load Diff
+1197
-662
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use de::{Deserialize, Deserializer, Error, Visitor};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub use de::content::{Content, ContentRefDeserializer, ContentDeserializer, TaggedContentVisitor,
|
||||
TagOrContentField, TagOrContentFieldVisitor, InternallyTaggedUnitVisitor,
|
||||
UntaggedUnitVisitor};
|
||||
|
||||
/// If the missing field is of type `Option<T>` then treat is as `None`,
|
||||
/// otherwise it is an error.
|
||||
pub fn missing_field<V, E>(field: &'static str) -> Result<V, E>
|
||||
where V: Deserialize,
|
||||
E: Error
|
||||
{
|
||||
struct MissingFieldDeserializer<E>(&'static str, PhantomData<E>);
|
||||
|
||||
impl<E> Deserializer for MissingFieldDeserializer<E>
|
||||
where E: Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize<V>(self, _visitor: V) -> Result<V::Value, E>
|
||||
where V: Visitor
|
||||
{
|
||||
Err(Error::missing_field(self.0))
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
|
||||
where V: Visitor
|
||||
{
|
||||
visitor.visit_none()
|
||||
}
|
||||
|
||||
forward_to_deserialize! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
|
||||
seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
tuple_struct struct struct_field tuple enum ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
let deserializer = MissingFieldDeserializer(field, PhantomData);
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
+738
-486
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
//! A stand-in for `std::error`
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
/// A stand-in for `std::error::Error`, which requires no allocation.
|
||||
pub trait Error: Debug + Display {
|
||||
/// A short description of the error.
|
||||
///
|
||||
/// The description should not contain newlines or sentence-ending
|
||||
/// punctuation, to facilitate embedding in larger user-facing
|
||||
/// strings.
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// The lower-level cause of this error, if any.
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
+42
-32
@@ -1,34 +1,44 @@
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::String;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::borrow::Cow;
|
||||
|
||||
pub use core::default::Default;
|
||||
pub use core::fmt;
|
||||
pub use core::marker::PhantomData;
|
||||
pub use core::option::Option::{self, None, Some};
|
||||
pub use core::result::Result::{self, Ok, Err};
|
||||
|
||||
#[cfg(any(feature = "collections", feature = "std"))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
|
||||
// The generated code calls this like:
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// 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 = "collections", feature = "std")))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
use core::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}")
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/// Conditional compilation depending on whether Serde is built with support for
|
||||
/// 128-bit integers.
|
||||
///
|
||||
/// Data formats that wish to support Rust compiler versions older than 1.26 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_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {
|
||||
$($tt)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(integer128))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {};
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
//! Module that contains helper iterators.
|
||||
|
||||
use std::io;
|
||||
use std::iter::Peekable;
|
||||
|
||||
/// Iterator over a byte stream that tracks the current position's line and column.
|
||||
pub struct LineColIterator<Iter: Iterator<Item = io::Result<u8>>> {
|
||||
iter: Iter,
|
||||
line: usize,
|
||||
col: usize,
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Iter> {
|
||||
/// Construct a new `LineColIterator<Iter>`.
|
||||
pub fn new(iter: Iter) -> LineColIterator<Iter> {
|
||||
LineColIterator {
|
||||
iter: iter,
|
||||
line: 1,
|
||||
col: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Report the current line inside the iterator.
|
||||
pub fn line(&self) -> usize {
|
||||
self.line
|
||||
}
|
||||
|
||||
/// Report the current column inside the iterator.
|
||||
pub fn col(&self) -> usize {
|
||||
self.col
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying iterator.
|
||||
pub fn get_ref(&self) -> &Iter {
|
||||
&self.iter
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying iterator.
|
||||
pub fn get_mut(&mut self) -> &mut Iter {
|
||||
&mut self.iter
|
||||
}
|
||||
|
||||
/// Unwraps this `LineColIterator`, returning the underlying iterator.
|
||||
pub fn into_inner(self) -> Iter {
|
||||
self.iter
|
||||
}
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Peekable<Iter>> {
|
||||
/// peeks at the next value
|
||||
pub fn peek(&mut self) -> Option<&io::Result<u8>> {
|
||||
self.iter.peek()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> Iterator for LineColIterator<Iter> {
|
||||
type Item = io::Result<u8>;
|
||||
fn next(&mut self) -> Option<io::Result<u8>> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(Ok(b'\n')) => {
|
||||
self.line += 1;
|
||||
self.col = 0;
|
||||
Some(Ok(b'\n'))
|
||||
}
|
||||
Some(Ok(c)) => {
|
||||
self.col += 1;
|
||||
Some(Ok(c))
|
||||
}
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
+238
-59
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! # Serde
|
||||
//!
|
||||
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
|
||||
@@ -9,99 +17,270 @@
|
||||
//! these two groups interact with each other, allowing any supported data
|
||||
//! structure to be serialized and deserialized using any supported data format.
|
||||
//!
|
||||
//! See the Serde website https://serde.rs/ for additional documentation and
|
||||
//! See the Serde website [https://serde.rs/] for additional documentation and
|
||||
//! usage examples.
|
||||
//!
|
||||
//! ### Design
|
||||
//! [https://serde.rs/]: https://serde.rs/
|
||||
//!
|
||||
//! ## Design
|
||||
//!
|
||||
//! Where many other languages rely on runtime reflection for serializing data,
|
||||
//! Serde is instead built on Rust's powerful trait system. A data structure
|
||||
//! that knows how to serialize and deserialize itself is one that implements
|
||||
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's code
|
||||
//! generation to automatically derive implementations at compile time). This
|
||||
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
|
||||
//! attribute to automatically generate implementations at compile time). This
|
||||
//! avoids any overhead of reflection or runtime type information. In fact in
|
||||
//! many situations the interaction between data structure and data format can
|
||||
//! be completely optimized away by the Rust compiler, leaving Serde
|
||||
//! serialization to perform roughly the same speed as a handwritten serializer
|
||||
//! for the specific selection of data structure and data format.
|
||||
//! serialization to perform the same speed as a handwritten serializer for the
|
||||
//! specific selection of data structure and data format.
|
||||
//!
|
||||
//! ### Data formats
|
||||
//! ## Data formats
|
||||
//!
|
||||
//! The following is a partial list of data formats that have been implemented
|
||||
//! for Serde by the community.
|
||||
//!
|
||||
//! - [JSON](https://github.com/serde-rs/json), the ubiquitous JavaScript Object
|
||||
//! Notation used by many HTTP APIs.
|
||||
//! - [Bincode](https://github.com/TyOverby/bincode), a compact binary format
|
||||
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
|
||||
//! - [Bincode], a compact binary format
|
||||
//! used for IPC within the Servo rendering engine.
|
||||
//! - [CBOR](https://github.com/pyfisch/cbor), a Concise Binary Object
|
||||
//! Representation designed for small message size without the need for
|
||||
//! version negotiation.
|
||||
//! - [YAML](https://github.com/dtolnay/serde-yaml), a popular human-friendly
|
||||
//! configuration language that ain't markup language.
|
||||
//! - [MessagePack](https://github.com/3Hren/msgpack-rust), an efficient binary
|
||||
//! format that resembles a compact JSON.
|
||||
//! - [TOML](https://github.com/alexcrichton/toml-rs), a minimal configuration
|
||||
//! format used by [Cargo](http://doc.crates.io/manifest.html).
|
||||
//! - [Pickle](https://github.com/birkenfeld/serde-pickle), a format common in
|
||||
//! the Python world.
|
||||
//! - [Hjson](https://github.com/laktak/hjson-rust), a variant of JSON designed
|
||||
//! to be readable and writable by humans.
|
||||
//! - [BSON](https://github.com/zonyitoo/bson-rs), the data storage and network
|
||||
//! transfer format used by MongoDB.
|
||||
//! - [URL](https://github.com/nox/serde_urlencoded), the x-www-form-urlencoded
|
||||
//! format.
|
||||
//! - [XML](https://github.com/serde-rs/xml), the flexible machine-friendly W3C
|
||||
//! standard. *(deserialization only)*
|
||||
//! - [Envy](https://github.com/softprops/envy), a way to deserialize
|
||||
//! environment variables into Rust structs. *(deserialization only)*
|
||||
//! - [Redis](https://github.com/OneSignal/serde-redis), deserialize values from
|
||||
//! Redis when using [redis-rs](https://crates.io/crates/redis).
|
||||
//! - [CBOR], a Concise Binary Object Representation designed for small message
|
||||
//! size without the need for version negotiation.
|
||||
//! - [YAML], a popular human-friendly configuration language that ain't markup
|
||||
//! language.
|
||||
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
|
||||
//! - [TOML], a minimal configuration format used by [Cargo].
|
||||
//! - [Pickle], a format common in the Python world.
|
||||
//! - [Hjson], a variant of JSON designed to be readable and writable by humans.
|
||||
//! - [BSON], the data storage and network transfer format used by MongoDB.
|
||||
//! - [URL], the x-www-form-urlencoded format.
|
||||
//! - [XML], the flexible machine-friendly W3C standard.
|
||||
//! *(deserialization only)*
|
||||
//! - [Envy], a way to deserialize environment variables into Rust structs.
|
||||
//! *(deserialization only)*
|
||||
//! - [Redis], deserialize values from Redis when using [redis-rs].
|
||||
//! *(deserialization only)*
|
||||
//!
|
||||
//! [JSON]: https://github.com/serde-rs/json
|
||||
//! [Bincode]: https://github.com/TyOverby/bincode
|
||||
//! [CBOR]: https://github.com/pyfisch/cbor
|
||||
//! [YAML]: https://github.com/dtolnay/serde-yaml
|
||||
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
|
||||
//! [TOML]: https://github.com/alexcrichton/toml-rs
|
||||
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
|
||||
//! [Hjson]: https://github.com/laktak/hjson-rust
|
||||
//! [BSON]: https://github.com/zonyitoo/bson-rs
|
||||
//! [URL]: https://github.com/nox/serde_urlencoded
|
||||
//! [XML]: https://github.com/RReverser/serde-xml-rs
|
||||
//! [Envy]: https://github.com/softprops/envy
|
||||
//! [Redis]: https://github.com/OneSignal/serde-redis
|
||||
//! [Cargo]: http://doc.crates.io/manifest.html
|
||||
//! [redis-rs]: https://crates.io/crates/redis
|
||||
|
||||
#![doc(html_root_url="https://docs.serde.rs")]
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.60")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(feature = "unstable", feature(inclusive_range, nonzero, specialization, zero_one))]
|
||||
// Unstable functionality only if the user asks for it. For tracking and
|
||||
// discussion of these features please refer to this issue:
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(specialization))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![cfg_attr(feature = "collections", feature(collections))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
cast_lossless, const_static_lifetime, doc_markdown, linkedlist, needless_pass_by_value,
|
||||
redundant_field_names, type_complexity, unreadable_literal, zero_prefixed_literal
|
||||
)
|
||||
)]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
cast_possible_truncation,
|
||||
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
|
||||
many_single_char_names,
|
||||
missing_docs_in_private_items,
|
||||
similar_names,
|
||||
// alternative is not stable
|
||||
empty_enum,
|
||||
use_debug,
|
||||
))]
|
||||
// Blacklisted Rust lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
extern crate collections;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
extern crate core as actual_core;
|
||||
#[cfg(all(feature = "unstable", feature = "std"))]
|
||||
extern crate core;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod core {
|
||||
pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize,
|
||||
usize, f32, f64, char, str, num, slice, iter, cell, default, result, option};
|
||||
#[cfg(feature = "unstable")]
|
||||
pub use actual_core::nonzero;
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use core::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
pub use self::core::{cmp, iter, mem, num, ops, slice, str};
|
||||
pub use self::core::{f32, f64};
|
||||
pub use self::core::{i16, i32, i64, i8, isize};
|
||||
pub use self::core::{u16, u32, u64, u8, usize};
|
||||
|
||||
pub use self::core::cell::{Cell, RefCell};
|
||||
pub use self::core::clone::{self, Clone};
|
||||
pub use self::core::convert::{self, From, Into};
|
||||
pub use self::core::default::{self, Default};
|
||||
pub use self::core::fmt::{self, Debug, Display};
|
||||
pub use self::core::marker::{self, PhantomData};
|
||||
pub use self::core::option::{self, Option};
|
||||
pub use self::core::result::{self, Result};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::String;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::boxed::Box;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::rc::{Rc, Weak as RcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::rc::{Rc, Weak as RcWeak};
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::arc::{Arc, Weak as ArcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::sync::{Arc, Weak as ArcWeak};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::{error, net};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::{CStr, CString, OsStr, OsString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::hash::{BuildHasher, Hash};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::Write;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::num::Wrapping;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
}
|
||||
|
||||
#[doc(inline)]
|
||||
pub use ser::{Serialize, Serializer};
|
||||
#[doc(inline)]
|
||||
pub use de::{Deserialize, Deserializer};
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod bytes;
|
||||
#[macro_use]
|
||||
mod integer128;
|
||||
|
||||
pub mod de;
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
pub mod iter;
|
||||
pub mod ser;
|
||||
#[cfg_attr(feature = "std", doc(hidden))]
|
||||
pub mod error;
|
||||
mod utils;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use de::{Deserialize, Deserializer};
|
||||
#[doc(inline)]
|
||||
pub use ser::{Serialize, Serializer};
|
||||
|
||||
// Generated code uses these to support no_std. Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod export;
|
||||
|
||||
// Helpers used by generated code and doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod private;
|
||||
|
||||
// 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
|
||||
// be annoying for crates that provide handwritten impls or data formats. They
|
||||
// would need to disable default features and then explicitly re-enable std.
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[doc(hidden)]
|
||||
pub use serde_derive::*;
|
||||
|
||||
+212
-178
@@ -1,122 +1,10 @@
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_method {
|
||||
($func:ident($($arg:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::std::result::Result<__V::Value, Self::Error>
|
||||
where __V: $crate::de::Visitor
|
||||
{
|
||||
self.deserialize(visitor)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_method {
|
||||
($func:ident($($arg:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::core::result::Result<__V::Value, Self::Error>
|
||||
where __V: $crate::de::Visitor
|
||||
{
|
||||
self.deserialize(visitor)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_helper {
|
||||
(bool) => {
|
||||
forward_to_deserialize_method!{deserialize_bool()}
|
||||
};
|
||||
(u8) => {
|
||||
forward_to_deserialize_method!{deserialize_u8()}
|
||||
};
|
||||
(u16) => {
|
||||
forward_to_deserialize_method!{deserialize_u16()}
|
||||
};
|
||||
(u32) => {
|
||||
forward_to_deserialize_method!{deserialize_u32()}
|
||||
};
|
||||
(u64) => {
|
||||
forward_to_deserialize_method!{deserialize_u64()}
|
||||
};
|
||||
(i8) => {
|
||||
forward_to_deserialize_method!{deserialize_i8()}
|
||||
};
|
||||
(i16) => {
|
||||
forward_to_deserialize_method!{deserialize_i16()}
|
||||
};
|
||||
(i32) => {
|
||||
forward_to_deserialize_method!{deserialize_i32()}
|
||||
};
|
||||
(i64) => {
|
||||
forward_to_deserialize_method!{deserialize_i64()}
|
||||
};
|
||||
(f32) => {
|
||||
forward_to_deserialize_method!{deserialize_f32()}
|
||||
};
|
||||
(f64) => {
|
||||
forward_to_deserialize_method!{deserialize_f64()}
|
||||
};
|
||||
(char) => {
|
||||
forward_to_deserialize_method!{deserialize_char()}
|
||||
};
|
||||
(str) => {
|
||||
forward_to_deserialize_method!{deserialize_str()}
|
||||
};
|
||||
(string) => {
|
||||
forward_to_deserialize_method!{deserialize_string()}
|
||||
};
|
||||
(unit) => {
|
||||
forward_to_deserialize_method!{deserialize_unit()}
|
||||
};
|
||||
(option) => {
|
||||
forward_to_deserialize_method!{deserialize_option()}
|
||||
};
|
||||
(seq) => {
|
||||
forward_to_deserialize_method!{deserialize_seq()}
|
||||
};
|
||||
(seq_fixed_size) => {
|
||||
forward_to_deserialize_method!{deserialize_seq_fixed_size(usize)}
|
||||
};
|
||||
(bytes) => {
|
||||
forward_to_deserialize_method!{deserialize_bytes()}
|
||||
};
|
||||
(byte_buf) => {
|
||||
forward_to_deserialize_method!{deserialize_byte_buf()}
|
||||
};
|
||||
(map) => {
|
||||
forward_to_deserialize_method!{deserialize_map()}
|
||||
};
|
||||
(unit_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_unit_struct(&'static str)}
|
||||
};
|
||||
(newtype_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_newtype_struct(&'static str)}
|
||||
};
|
||||
(tuple_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_tuple_struct(&'static str, usize)}
|
||||
};
|
||||
(struct) => {
|
||||
forward_to_deserialize_method!{deserialize_struct(&'static str, &'static [&'static str])}
|
||||
};
|
||||
(struct_field) => {
|
||||
forward_to_deserialize_method!{deserialize_struct_field()}
|
||||
};
|
||||
(tuple) => {
|
||||
forward_to_deserialize_method!{deserialize_tuple(usize)}
|
||||
};
|
||||
(enum) => {
|
||||
forward_to_deserialize_method!{deserialize_enum(&'static str, &'static [&'static str])}
|
||||
};
|
||||
(ignored_any) => {
|
||||
forward_to_deserialize_method!{deserialize_ignored_any()}
|
||||
};
|
||||
}
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Super explicit first paragraph because this shows up at the top level and
|
||||
// trips up people who are just looking for basic Serialize / Deserialize
|
||||
@@ -125,98 +13,244 @@ macro_rules! forward_to_deserialize_helper {
|
||||
/// Helper macro when implementing the `Deserializer` part of a new data format
|
||||
/// for Serde.
|
||||
///
|
||||
/// Some `Deserializer` implementations for self-describing formats do not care
|
||||
/// what hint the `Visitor` gives them, they just want to blindly call the
|
||||
/// `Visitor` method corresponding to the data they can tell is in the input.
|
||||
/// This requires repetitive implementations of all the `Deserializer` trait
|
||||
/// methods.
|
||||
/// Some [`Deserializer`] implementations for self-describing formats do not
|
||||
/// care what hint the [`Visitor`] gives them, they just want to blindly call
|
||||
/// the [`Visitor`] method corresponding to the data they can tell is in the
|
||||
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
||||
/// trait methods.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// # pub struct MyDeserializer;
|
||||
/// # impl Deserializer for MyDeserializer {
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
/// #
|
||||
/// # impl<'de> Deserializer<'de> for MyDeserializer {
|
||||
/// # type Error = value::Error;
|
||||
/// # fn deserialize<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// #[inline]
|
||||
/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// self.deserialize(visitor)
|
||||
/// self.deserialize_any(visitor)
|
||||
/// }
|
||||
/// # forward_to_deserialize! {
|
||||
/// # u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
|
||||
/// # seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
/// # tuple_struct struct struct_field tuple enum ignored_any
|
||||
/// #
|
||||
/// # forward_to_deserialize_any! {
|
||||
/// # 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
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// The `forward_to_deserialize!` macro implements these simple forwarding
|
||||
/// methods so that they forward directly to `Deserializer::deserialize`. You
|
||||
/// can choose which methods to forward.
|
||||
/// The `forward_to_deserialize_any!` macro implements these simple forwarding
|
||||
/// methods so that they forward directly to [`Deserializer::deserialize_any`].
|
||||
/// You can choose which methods to forward.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde;
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// # pub struct MyDeserializer;
|
||||
/// impl Deserializer for MyDeserializer {
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
/// #
|
||||
/// impl<'de> Deserializer<'de> for MyDeserializer {
|
||||
/// # type Error = value::Error;
|
||||
/// fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor
|
||||
/// #
|
||||
/// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// /* ... */
|
||||
/// # let _ = visitor;
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// forward_to_deserialize! {
|
||||
/// bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
|
||||
/// seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
/// tuple_struct struct struct_field tuple enum ignored_any
|
||||
/// 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
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// The macro assumes the convention that your `Deserializer` lifetime parameter
|
||||
/// is called `'de` and that the `Visitor` type parameters on each method are
|
||||
/// called `V`. A different type parameter and a different lifetime can be
|
||||
/// specified explicitly if necessary.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// # use std::marker::PhantomData;
|
||||
/// #
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// #
|
||||
/// # struct MyDeserializer<V>(PhantomData<V>);
|
||||
/// #
|
||||
/// # impl<'q, V> Deserializer<'q> for MyDeserializer<V> {
|
||||
/// # type Error = value::Error;
|
||||
/// #
|
||||
/// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error>
|
||||
/// # where
|
||||
/// # W: Visitor<'q>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// forward_to_deserialize_any! {
|
||||
/// <W: Visitor<'q>>
|
||||
/// 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
|
||||
/// }
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`Deserializer`]: trait.Deserializer.html
|
||||
/// [`Visitor`]: de/trait.Visitor.html
|
||||
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize {
|
||||
macro_rules! forward_to_deserialize_any {
|
||||
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
|
||||
$(forward_to_deserialize_any_helper!{$func<$lifetime, $visitor>})*
|
||||
};
|
||||
// This case must be after the previous one.
|
||||
($($func:ident)*) => {
|
||||
$(forward_to_deserialize_helper!{$func})*
|
||||
$(forward_to_deserialize_any_helper!{$func<'de, V>})*
|
||||
};
|
||||
}
|
||||
|
||||
/// Seralize the `$value` that implements Display as a string,
|
||||
/// when that string is statically known to never have more than
|
||||
/// a constant `$MAX_LEN` bytes.
|
||||
///
|
||||
/// Panics if the Display impl tries to write more than `$MAX_LEN` bytes.
|
||||
#[cfg(feature = "std")]
|
||||
// Not exported
|
||||
macro_rules! serialize_display_bounded_length {
|
||||
($value: expr, $MAX_LEN: expr, $serializer: expr) => {
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_any_method {
|
||||
($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::export::Result<$v::Value, Self::Error>
|
||||
where
|
||||
$v: $crate::de::Visitor<$l>,
|
||||
{
|
||||
use std::io::Write;
|
||||
let mut buffer: [u8; $MAX_LEN] = unsafe { ::std::mem::uninitialized() };
|
||||
let remaining_len;
|
||||
{
|
||||
let mut remaining = &mut buffer[..];
|
||||
write!(remaining, "{}", $value).unwrap();
|
||||
remaining_len = remaining.len()
|
||||
}
|
||||
let written_len = buffer.len() - remaining_len;
|
||||
let written = &buffer[..written_len];
|
||||
|
||||
// write! only provides std::fmt::Formatter to Display implementations,
|
||||
// which has methods write_str and write_char but no method to write arbitrary bytes.
|
||||
// Therefore, `written` is well-formed in UTF-8.
|
||||
let written_str = unsafe {
|
||||
::std::str::from_utf8_unchecked(written)
|
||||
};
|
||||
$serializer.serialize_str(written_str)
|
||||
$(
|
||||
let _ = $arg;
|
||||
)*
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_any_helper {
|
||||
(bool<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()}
|
||||
};
|
||||
(i8<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i8<$l, $v>()}
|
||||
};
|
||||
(i16<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i16<$l, $v>()}
|
||||
};
|
||||
(i32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i32<$l, $v>()}
|
||||
};
|
||||
(i64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
|
||||
};
|
||||
(i128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()}
|
||||
}
|
||||
};
|
||||
(u8<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
|
||||
};
|
||||
(u16<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u16<$l, $v>()}
|
||||
};
|
||||
(u32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u32<$l, $v>()}
|
||||
};
|
||||
(u64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
|
||||
};
|
||||
(u128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()}
|
||||
}
|
||||
};
|
||||
(f32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()}
|
||||
};
|
||||
(f64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_f64<$l, $v>()}
|
||||
};
|
||||
(char<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_char<$l, $v>()}
|
||||
};
|
||||
(str<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_str<$l, $v>()}
|
||||
};
|
||||
(string<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_string<$l, $v>()}
|
||||
};
|
||||
(bytes<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_bytes<$l, $v>()}
|
||||
};
|
||||
(byte_buf<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_byte_buf<$l, $v>()}
|
||||
};
|
||||
(option<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_option<$l, $v>()}
|
||||
};
|
||||
(unit<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_unit<$l, $v>()}
|
||||
};
|
||||
(unit_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_unit_struct<$l, $v>(name: &'static str)}
|
||||
};
|
||||
(newtype_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_newtype_struct<$l, $v>(name: &'static str)}
|
||||
};
|
||||
(seq<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_seq<$l, $v>()}
|
||||
};
|
||||
(tuple<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_tuple<$l, $v>(len: usize)}
|
||||
};
|
||||
(tuple_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_tuple_struct<$l, $v>(name: &'static str, len: usize)}
|
||||
};
|
||||
(map<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_map<$l, $v>()}
|
||||
};
|
||||
(struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_struct<$l, $v>(name: &'static str, fields: &'static [&'static str])}
|
||||
};
|
||||
(enum<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_enum<$l, $v>(name: &'static str, variants: &'static [&'static str])}
|
||||
};
|
||||
(identifier<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_identifier<$l, $v>()}
|
||||
};
|
||||
(ignored_any<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_ignored_any<$l, $v>()}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,148 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __private_serialize {
|
||||
() => {
|
||||
trait Serialize {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: $crate::Serializer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[macro_export]
|
||||
macro_rules! __serialize_unimplemented {
|
||||
($($func:ident)*) => {
|
||||
$(
|
||||
__serialize_unimplemented_helper!($func);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __serialize_unimplemented_method {
|
||||
($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
|
||||
fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::export::Result<Self::$ret, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __serialize_unimplemented_helper {
|
||||
(bool) => {
|
||||
__serialize_unimplemented_method!(serialize_bool(bool) -> Ok);
|
||||
};
|
||||
(i8) => {
|
||||
__serialize_unimplemented_method!(serialize_i8(i8) -> Ok);
|
||||
};
|
||||
(i16) => {
|
||||
__serialize_unimplemented_method!(serialize_i16(i16) -> Ok);
|
||||
};
|
||||
(i32) => {
|
||||
__serialize_unimplemented_method!(serialize_i32(i32) -> Ok);
|
||||
};
|
||||
(i64) => {
|
||||
__serialize_unimplemented_method!(serialize_i64(i64) -> Ok);
|
||||
};
|
||||
(u8) => {
|
||||
__serialize_unimplemented_method!(serialize_u8(u8) -> Ok);
|
||||
};
|
||||
(u16) => {
|
||||
__serialize_unimplemented_method!(serialize_u16(u16) -> Ok);
|
||||
};
|
||||
(u32) => {
|
||||
__serialize_unimplemented_method!(serialize_u32(u32) -> Ok);
|
||||
};
|
||||
(u64) => {
|
||||
__serialize_unimplemented_method!(serialize_u64(u64) -> Ok);
|
||||
};
|
||||
(f32) => {
|
||||
__serialize_unimplemented_method!(serialize_f32(f32) -> Ok);
|
||||
};
|
||||
(f64) => {
|
||||
__serialize_unimplemented_method!(serialize_f64(f64) -> Ok);
|
||||
};
|
||||
(char) => {
|
||||
__serialize_unimplemented_method!(serialize_char(char) -> Ok);
|
||||
};
|
||||
(str) => {
|
||||
__serialize_unimplemented_method!(serialize_str(&str) -> Ok);
|
||||
};
|
||||
(bytes) => {
|
||||
__serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok);
|
||||
};
|
||||
(none) => {
|
||||
__serialize_unimplemented_method!(serialize_none() -> Ok);
|
||||
};
|
||||
(some) => {
|
||||
__serialize_unimplemented_method!(serialize_some<T>(&T) -> Ok);
|
||||
};
|
||||
(unit) => {
|
||||
__serialize_unimplemented_method!(serialize_unit() -> Ok);
|
||||
};
|
||||
(unit_struct) => {
|
||||
__serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok);
|
||||
};
|
||||
(unit_variant) => {
|
||||
__serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok);
|
||||
};
|
||||
(newtype_struct) => {
|
||||
__serialize_unimplemented_method!(serialize_newtype_struct<T>(&str, &T) -> Ok);
|
||||
};
|
||||
(newtype_variant) => {
|
||||
__serialize_unimplemented_method!(serialize_newtype_variant<T>(&str, u32, &str, &T) -> Ok);
|
||||
};
|
||||
(seq) => {
|
||||
type SerializeSeq = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_seq(Option<usize>) -> SerializeSeq);
|
||||
};
|
||||
(tuple) => {
|
||||
type SerializeTuple = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple);
|
||||
};
|
||||
(tuple_struct) => {
|
||||
type SerializeTupleStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct);
|
||||
};
|
||||
(tuple_variant) => {
|
||||
type SerializeTupleVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant);
|
||||
};
|
||||
(map) => {
|
||||
type SerializeMap = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_map(Option<usize>) -> SerializeMap);
|
||||
};
|
||||
(struct) => {
|
||||
type SerializeStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct);
|
||||
};
|
||||
(struct_variant) => {
|
||||
type SerializeStructVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
mod macros;
|
||||
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
File diff suppressed because it is too large
Load Diff
+545
-503
File diff suppressed because it is too large
Load Diff
+124
-51
@@ -1,19 +1,37 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This module contains `Impossible` serializer and its implementations.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use lib::*;
|
||||
|
||||
use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
|
||||
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant};
|
||||
use ser::{
|
||||
self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
|
||||
};
|
||||
|
||||
/// Helper type for implementing a `Serializer` that does not support
|
||||
/// serializing one of the compound types.
|
||||
///
|
||||
/// This type cannot be instantiated, but implements every one of the traits
|
||||
/// corresponding to the `Serializer` compound types: `SerializeSeq`,
|
||||
/// `SerializeTuple`, `SerializeTupleStruct`, `SerializeTupleVariant`,
|
||||
/// `SerializeMap`, `SerializeStruct`, and `SerializeStructVariant`.
|
||||
/// corresponding to the [`Serializer`] compound types: [`SerializeSeq`],
|
||||
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
||||
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// # use serde::ser::{Serializer, Impossible};
|
||||
/// # use serde::private::ser::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
/// impl Serializer for MySerializer {
|
||||
/// type Ok = ();
|
||||
/// type Error = Error;
|
||||
@@ -27,130 +45,185 @@ use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
|
||||
/// -> Result<Self::SerializeSeq, Error> {
|
||||
/// // Given Impossible cannot be instantiated, the only
|
||||
/// // thing we can do here is to return an error.
|
||||
/// # stringify! {
|
||||
/// Err(...)
|
||||
/// # };
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// /* other Serializer methods */
|
||||
/// # __serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant
|
||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||
/// # }
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
pub struct Impossible<Ok, E> {
|
||||
///
|
||||
/// [`Serializer`]: trait.Serializer.html
|
||||
/// [`SerializeSeq`]: trait.SerializeSeq.html
|
||||
/// [`SerializeTuple`]: trait.SerializeTuple.html
|
||||
/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html
|
||||
/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html
|
||||
/// [`SerializeMap`]: trait.SerializeMap.html
|
||||
/// [`SerializeStruct`]: trait.SerializeStruct.html
|
||||
/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html
|
||||
pub struct Impossible<Ok, Error> {
|
||||
void: Void,
|
||||
_marker: PhantomData<(Ok, E)>,
|
||||
ok: PhantomData<Ok>,
|
||||
error: PhantomData<Error>,
|
||||
}
|
||||
|
||||
enum Void {}
|
||||
|
||||
impl<Ok, E> SerializeSeq for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeSeq for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTuple for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTuple for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTupleStruct for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTupleStruct for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTupleVariant for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTupleVariant for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeMap for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeMap for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), E> {
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeStruct for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeStruct for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T)
|
||||
-> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeStructVariant for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeStructVariant for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T)
|
||||
-> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
+1478
-329
File diff suppressed because it is too large
Load Diff
@@ -1,262 +0,0 @@
|
||||
use core::fmt::{self, Display};
|
||||
|
||||
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct};
|
||||
|
||||
/// Not public API.
|
||||
pub fn serialize_tagged_newtype<S, T>(serializer: S,
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
tag: &'static str,
|
||||
variant_name: &'static str,
|
||||
value: T)
|
||||
-> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
T: Serialize
|
||||
{
|
||||
value.serialize(TaggedSerializer {
|
||||
type_ident: type_ident,
|
||||
variant_ident: variant_ident,
|
||||
tag: tag,
|
||||
variant_name: variant_name,
|
||||
delegate: serializer,
|
||||
})
|
||||
}
|
||||
|
||||
struct TaggedSerializer<S> {
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
tag: &'static str,
|
||||
variant_name: &'static str,
|
||||
delegate: S,
|
||||
}
|
||||
|
||||
enum Unsupported {
|
||||
Boolean,
|
||||
Integer,
|
||||
Float,
|
||||
Char,
|
||||
String,
|
||||
ByteArray,
|
||||
Optional,
|
||||
Unit,
|
||||
UnitStruct,
|
||||
Sequence,
|
||||
Tuple,
|
||||
TupleStruct,
|
||||
Enum,
|
||||
}
|
||||
|
||||
impl Display for Unsupported {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Unsupported::Boolean => formatter.write_str("a boolean"),
|
||||
Unsupported::Integer => formatter.write_str("an integer"),
|
||||
Unsupported::Float => formatter.write_str("a float"),
|
||||
Unsupported::Char => formatter.write_str("a char"),
|
||||
Unsupported::String => formatter.write_str("a string"),
|
||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||
Unsupported::Optional => formatter.write_str("an optional"),
|
||||
Unsupported::Unit => formatter.write_str("unit"),
|
||||
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
|
||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||
Unsupported::Enum => formatter.write_str("an enum"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Error {
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
ty: Unsupported,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter,
|
||||
"cannot serialize tagged newtype variant {}::{} containing {}",
|
||||
self.type_ident, self.variant_ident, self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> TaggedSerializer<S>
|
||||
where S: Serializer
|
||||
{
|
||||
fn bad_type(self, what: Unsupported) -> S::Error {
|
||||
ser::Error::custom(Error {
|
||||
type_ident: self.type_ident,
|
||||
variant_ident: self.variant_ident,
|
||||
ty: what,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Serializer for TaggedSerializer<S>
|
||||
where S: Serializer
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
|
||||
type SerializeSeq = S::SerializeSeq;
|
||||
type SerializeTuple = S::SerializeTuple;
|
||||
type SerializeTupleStruct = S::SerializeTupleStruct;
|
||||
type SerializeTupleVariant = S::SerializeTupleVariant;
|
||||
type SerializeMap = S::SerializeMap;
|
||||
type SerializeStruct = S::SerializeStruct;
|
||||
type SerializeStructVariant = S::SerializeStructVariant;
|
||||
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Boolean))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Char))
|
||||
}
|
||||
|
||||
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::String))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::ByteArray))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Unit))
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::UnitStruct))
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str)
|
||||
-> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(self,
|
||||
_: &'static str,
|
||||
value: &T)
|
||||
-> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str,
|
||||
_: &T)
|
||||
-> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Sequence))
|
||||
}
|
||||
|
||||
fn serialize_seq_fixed_size(self, _: usize) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Sequence))
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Tuple))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::TupleStruct))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
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)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
fn serialize_struct(self,
|
||||
name: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeStruct, Self::Error> {
|
||||
let mut state = try!(self.delegate.serialize_struct(name, len + 1));
|
||||
try!(state.serialize_field(self.tag, self.variant_name));
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//! Private utility functions
|
||||
|
||||
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_utf8(c: char) -> EncodeUtf8 {
|
||||
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
|
||||
};
|
||||
EncodeUtf8 {
|
||||
buf: buf,
|
||||
pos: pos,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EncodeUtf8 {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl EncodeUtf8 {
|
||||
// FIXME: use this from_utf8_unchecked, since we know it can never fail
|
||||
pub fn as_str(&self) -> &str {
|
||||
::core::str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const Pattern_White_Space_table: &'static [(char, char)] = &[('\u{9}', '\u{d}'),
|
||||
('\u{20}', '\u{20}'),
|
||||
('\u{85}', '\u{85}'),
|
||||
('\u{200e}', '\u{200f}'),
|
||||
('\u{2028}', '\u{2029}')];
|
||||
|
||||
fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
r.binary_search_by(|&(lo, hi)| if c < lo {
|
||||
Greater
|
||||
} else if hi < c {
|
||||
Less
|
||||
} else {
|
||||
Equal
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Pattern_White_Space(c: char) -> bool {
|
||||
bsearch_range_table(c, Pattern_White_Space_table)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
[package]
|
||||
name = "serde_codegen_internals"
|
||||
version = "0.14.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "AST representation used by Serde codegen. Unstable."
|
||||
homepage = "https://serde.rs"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://docs.serde.rs/serde_codegen_internals/"
|
||||
keywords = ["serde", "serialization"]
|
||||
readme = "../README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "0.11", default-features = false, features = ["parsing"] }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
@@ -1,106 +0,0 @@
|
||||
use syn;
|
||||
use attr;
|
||||
use Ctxt;
|
||||
|
||||
pub struct Item<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Item,
|
||||
pub body: Body<'a>,
|
||||
pub generics: &'a syn::Generics,
|
||||
}
|
||||
|
||||
pub enum Body<'a> {
|
||||
Enum(Vec<Variant<'a>>),
|
||||
Struct(Style, Vec<Field<'a>>),
|
||||
}
|
||||
|
||||
pub struct Variant<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Variant,
|
||||
pub style: Style,
|
||||
pub fields: Vec<Field<'a>>,
|
||||
}
|
||||
|
||||
pub struct Field<'a> {
|
||||
pub ident: Option<syn::Ident>,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Ty,
|
||||
}
|
||||
|
||||
pub enum Style {
|
||||
Struct,
|
||||
Tuple,
|
||||
Newtype,
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a> Item<'a> {
|
||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Item<'a> {
|
||||
let attrs = attr::Item::from_ast(cx, item);
|
||||
|
||||
let body = match item.body {
|
||||
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
|
||||
syn::Body::Struct(ref variant_data) => {
|
||||
let (style, fields) = struct_from_ast(cx, variant_data);
|
||||
Body::Struct(style, fields)
|
||||
}
|
||||
};
|
||||
|
||||
Item {
|
||||
ident: item.ident.clone(),
|
||||
attrs: attrs,
|
||||
body: body,
|
||||
generics: &item.generics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Body<'a> {
|
||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
||||
match *self {
|
||||
Body::Enum(ref variants) => {
|
||||
Box::new(variants.iter()
|
||||
.flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Body::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
|
||||
variants.iter()
|
||||
.map(|variant| {
|
||||
let (style, fields) = struct_from_ast(cx, &variant.data);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs: attr::Variant::from_ast(cx, variant),
|
||||
style: style,
|
||||
fields: fields,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) {
|
||||
match *data {
|
||||
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)),
|
||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
||||
(Style::Newtype, fields_from_ast(cx, fields))
|
||||
}
|
||||
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)),
|
||||
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
Field {
|
||||
ident: field.ident.clone(),
|
||||
attrs: attr::Field::from_ast(cx, i, field),
|
||||
ty: &field.ty,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -1,715 +0,0 @@
|
||||
use Ctxt;
|
||||
use syn;
|
||||
use syn::MetaItem::{List, NameValue, Word};
|
||||
use syn::NestedMetaItem::{Literal, MetaItem};
|
||||
|
||||
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
|
||||
// are `attr::Item::from_ast`, `attr::Variant::from_ast`, and
|
||||
// `attr::Field::from_ast`. Each returns an instance of the corresponding
|
||||
// struct. Note that none of them return a Result. Unrecognized, malformed, or
|
||||
// duplicated attributes result in a span_err but otherwise are ignored. The
|
||||
// user will see errors simultaneously for all bad attributes in the crate
|
||||
// rather than just the first.
|
||||
|
||||
struct Attr<'c, T> {
|
||||
cx: &'c Ctxt,
|
||||
name: &'static str,
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
impl<'c, T> Attr<'c, T> {
|
||||
fn none(cx: &'c Ctxt, name: &'static str) -> Self {
|
||||
Attr {
|
||||
cx: cx,
|
||||
name: name,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, value: T) {
|
||||
if self.value.is_some() {
|
||||
self.cx.error(format!("duplicate serde attribute `{}`", self.name));
|
||||
} else {
|
||||
self.value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_opt(&mut self, value: Option<T>) {
|
||||
if let Some(value) = value {
|
||||
self.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_if_none(&mut self, value: T) {
|
||||
if self.value.is_none() {
|
||||
self.value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn get(self) -> Option<T> {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
struct BoolAttr<'c>(Attr<'c, ()>);
|
||||
|
||||
impl<'c> BoolAttr<'c> {
|
||||
fn none(cx: &'c Ctxt, name: &'static str) -> Self {
|
||||
BoolAttr(Attr::none(cx, name))
|
||||
}
|
||||
|
||||
fn set_true(&mut self) {
|
||||
self.0.set(());
|
||||
}
|
||||
|
||||
fn get(&self) -> bool {
|
||||
self.0.value.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Name {
|
||||
serialize: String,
|
||||
deserialize: String,
|
||||
}
|
||||
|
||||
impl Name {
|
||||
/// Return the container name for the container when serializing.
|
||||
pub fn serialize_name(&self) -> String {
|
||||
self.serialize.clone()
|
||||
}
|
||||
|
||||
/// Return the container name for the container when deserializing.
|
||||
pub fn deserialize_name(&self) -> String {
|
||||
self.deserialize.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents container (e.g. struct) attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Item {
|
||||
name: Name,
|
||||
deny_unknown_fields: bool,
|
||||
default: Default,
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
tag: EnumTag,
|
||||
}
|
||||
|
||||
/// Styles of representing an enum.
|
||||
#[derive(Debug)]
|
||||
pub enum EnumTag {
|
||||
/// The default.
|
||||
///
|
||||
/// ```json
|
||||
/// {"variant1": {"key1": "value1", "key2": "value2"}}
|
||||
/// ```
|
||||
External,
|
||||
|
||||
/// `#[serde(tag = "type")]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"type": "variant1", "key1": "value1", "key2": "value2"}
|
||||
/// ```
|
||||
Internal { tag: String },
|
||||
|
||||
/// `#[serde(tag = "t", content = "c")]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
|
||||
/// ```
|
||||
Adjacent { tag: String, content: String },
|
||||
|
||||
/// `#[serde(untagged)]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"key1": "value1", "key2": "value2"}
|
||||
/// ```
|
||||
None,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
/// Extract out the `#[serde(...)]` attributes from an item.
|
||||
pub fn from_ast(cx: &Ctxt, item: &syn::MacroInput) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
|
||||
let mut default = Attr::none(cx, "default");
|
||||
let mut ser_bound = Attr::none(cx, "bound");
|
||||
let mut de_bound = Attr::none(cx, "bound");
|
||||
let mut untagged = BoolAttr::none(cx, "untagged");
|
||||
let mut internal_tag = Attr::none(cx, "tag");
|
||||
let mut content = Attr::none(cx, "content");
|
||||
|
||||
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deny_unknown_fields)]`
|
||||
MetaItem(Word(ref name)) if name == "deny_unknown_fields" => {
|
||||
deny_unknown_fields.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(default)]`
|
||||
MetaItem(Word(ref name)) if name == "default" => {
|
||||
match item.body {
|
||||
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||
default.set(Default::Default);
|
||||
}
|
||||
_ => {
|
||||
cx.error("#[serde(default)] can only be used on structs \
|
||||
with named fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(default="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||
default.set(Default::Path(path));
|
||||
}
|
||||
_ => {
|
||||
cx.error("#[serde(default = \"...\")] can only be used \
|
||||
on structs with named fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
|
||||
if let Ok(where_predicates) =
|
||||
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_bound.set(where_predicates.clone());
|
||||
de_bound.set(where_predicates);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
|
||||
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
|
||||
ser_bound.set_opt(ser);
|
||||
de_bound.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(untagged)]`
|
||||
MetaItem(Word(ref name)) if name == "untagged" => {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
untagged.set_true();
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(untagged)] can only be used on enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(tag = "type")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "tag" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
internal_tag.set(s);
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(tag = \"...\")] can only be used on enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(content = "c")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "content" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
content.set(s);
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(content = \"...\")] can only be used on enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde container attribute `{}`",
|
||||
meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde container attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tag = match (untagged.get(), internal_tag.get(), content.get()) {
|
||||
(false, None, None) => EnumTag::External,
|
||||
(true, None, None) => EnumTag::None,
|
||||
(false, Some(tag), None) => {
|
||||
// Check that there are no tuple variants.
|
||||
if let syn::Body::Enum(ref variants) = item.body {
|
||||
for variant in variants {
|
||||
match variant.data {
|
||||
syn::VariantData::Struct(_) |
|
||||
syn::VariantData::Unit => {}
|
||||
syn::VariantData::Tuple(ref fields) => {
|
||||
if fields.len() != 1 {
|
||||
cx.error("#[serde(tag = \"...\")] cannot be used with tuple \
|
||||
variants");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EnumTag::Internal { tag: tag }
|
||||
}
|
||||
(true, Some(_), None) => {
|
||||
cx.error("enum cannot be both untagged and internally tagged");
|
||||
EnumTag::External // doesn't matter, will error
|
||||
}
|
||||
(false, None, Some(_)) => {
|
||||
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
|
||||
EnumTag::External
|
||||
}
|
||||
(true, None, Some(_)) => {
|
||||
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
|
||||
EnumTag::External
|
||||
}
|
||||
(false, Some(tag), Some(content)) => {
|
||||
EnumTag::Adjacent { tag: tag, content: content }
|
||||
}
|
||||
(true, Some(_), Some(_)) => {
|
||||
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
|
||||
EnumTag::External
|
||||
}
|
||||
};
|
||||
|
||||
Item {
|
||||
name: Name {
|
||||
serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()),
|
||||
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
|
||||
},
|
||||
deny_unknown_fields: deny_unknown_fields.get(),
|
||||
default: default.get().unwrap_or(Default::None),
|
||||
ser_bound: ser_bound.get(),
|
||||
de_bound: de_bound.get(),
|
||||
tag: tag,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn deny_unknown_fields(&self) -> bool {
|
||||
self.deny_unknown_fields
|
||||
}
|
||||
|
||||
pub fn default(&self) -> &Default {
|
||||
&self.default
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> &EnumTag {
|
||||
&self.tag
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents variant attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Variant {
|
||||
name: Name,
|
||||
skip_deserializing: bool,
|
||||
skip_serializing: bool,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
|
||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
// Parse `#[serde(skip_deserializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
|
||||
skip_deserializing.set_true();
|
||||
}
|
||||
// Parse `#[serde(skip_serializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_serializing" => {
|
||||
skip_serializing.set_true();
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde variant attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant {
|
||||
name: Name {
|
||||
serialize: ser_name.get().unwrap_or_else(|| variant.ident.to_string()),
|
||||
deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()),
|
||||
},
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn skip_deserializing(&self) -> bool {
|
||||
self.skip_deserializing
|
||||
}
|
||||
|
||||
pub fn skip_serializing(&self) -> bool {
|
||||
self.skip_serializing
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Field {
|
||||
name: Name,
|
||||
skip_serializing: bool,
|
||||
skip_deserializing: bool,
|
||||
skip_serializing_if: Option<syn::Path>,
|
||||
default: Default,
|
||||
serialize_with: Option<syn::Path>,
|
||||
deserialize_with: Option<syn::Path>,
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
}
|
||||
|
||||
/// Represents the default to use for a field when deserializing.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Default {
|
||||
/// Field must always be specified because it does not have a default.
|
||||
None,
|
||||
/// The default is given by `std::default::Default::default()`.
|
||||
Default,
|
||||
/// The default is given by this function.
|
||||
Path(syn::Path),
|
||||
}
|
||||
|
||||
impl Field {
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
||||
let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if");
|
||||
let mut default = Attr::none(cx, "default");
|
||||
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||
let mut ser_bound = Attr::none(cx, "bound");
|
||||
let mut de_bound = Attr::none(cx, "bound");
|
||||
|
||||
let ident = match field.ident {
|
||||
Some(ref ident) => ident.to_string(),
|
||||
None => index.to_string(),
|
||||
};
|
||||
|
||||
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(default)]`
|
||||
MetaItem(Word(ref name)) if name == "default" => {
|
||||
default.set(Default::Default);
|
||||
}
|
||||
|
||||
// Parse `#[serde(default="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
default.set(Default::Path(path));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_serializing" => {
|
||||
skip_serializing.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_deserializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
|
||||
skip_deserializing.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing_if="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
skip_serializing_if.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
serialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
deserialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
let mut ser_path = path.clone();
|
||||
ser_path.segments.push("serialize".into());
|
||||
serialize_with.set(ser_path);
|
||||
let mut de_path = path;
|
||||
de_path.segments.push("deserialize".into());
|
||||
deserialize_with.set(de_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
|
||||
if let Ok(where_predicates) =
|
||||
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_bound.set(where_predicates.clone());
|
||||
de_bound.set(where_predicates);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
|
||||
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
|
||||
ser_bound.set_opt(ser);
|
||||
de_bound.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde field attribute `{}`", meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde field attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is skip_deserializing, initialize the field to Default::default()
|
||||
// unless a different default is specified by `#[serde(default="...")]`
|
||||
if skip_deserializing.0.value.is_some() {
|
||||
default.set_if_none(Default::Default);
|
||||
}
|
||||
|
||||
Field {
|
||||
name: Name {
|
||||
serialize: ser_name.get().unwrap_or_else(|| ident.clone()),
|
||||
deserialize: de_name.get().unwrap_or(ident),
|
||||
},
|
||||
skip_serializing: skip_serializing.get(),
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing_if: skip_serializing_if.get(),
|
||||
default: default.get().unwrap_or(Default::None),
|
||||
serialize_with: serialize_with.get(),
|
||||
deserialize_with: deserialize_with.get(),
|
||||
ser_bound: ser_bound.get(),
|
||||
de_bound: de_bound.get(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn skip_serializing(&self) -> bool {
|
||||
self.skip_serializing
|
||||
}
|
||||
|
||||
pub fn skip_deserializing(&self) -> bool {
|
||||
self.skip_deserializing
|
||||
}
|
||||
|
||||
pub fn skip_serializing_if(&self) -> Option<&syn::Path> {
|
||||
self.skip_serializing_if.as_ref()
|
||||
}
|
||||
|
||||
pub fn default(&self) -> &Default {
|
||||
&self.default
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
}
|
||||
|
||||
type SerAndDe<T> = (Option<T>, Option<T>);
|
||||
|
||||
fn get_ser_and_de<T, F>(cx: &Ctxt,
|
||||
attr_name: &'static str,
|
||||
items: &[syn::NestedMetaItem],
|
||||
f: F)
|
||||
-> Result<SerAndDe<T>, ()>
|
||||
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>
|
||||
{
|
||||
let mut ser_item = Attr::none(cx, attr_name);
|
||||
let mut de_item = Attr::none(cx, attr_name);
|
||||
|
||||
for item in items {
|
||||
match *item {
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => {
|
||||
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
|
||||
ser_item.set(v);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => {
|
||||
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
|
||||
de_item.set(v);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., \
|
||||
deserialize = ...)`",
|
||||
attr_name));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((ser_item.get(), de_item.get()))
|
||||
}
|
||||
|
||||
fn get_renames(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result<SerAndDe<String>, ()> {
|
||||
get_ser_and_de(cx, "rename", items, get_string_from_lit)
|
||||
}
|
||||
|
||||
fn get_where_predicates(cx: &Ctxt,
|
||||
items: &[syn::NestedMetaItem])
|
||||
-> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
|
||||
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
|
||||
}
|
||||
|
||||
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMetaItem>> {
|
||||
match attr.value {
|
||||
List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string_from_lit(cx: &Ctxt,
|
||||
attr_name: &str,
|
||||
meta_item_name: &str,
|
||||
lit: &syn::Lit)
|
||||
-> Result<String, ()> {
|
||||
if let syn::Lit::Str(ref s, _) = *lit {
|
||||
Ok(s.clone())
|
||||
} else {
|
||||
cx.error(format!("expected serde {} attribute to be a string: `{} = \"...\"`",
|
||||
attr_name,
|
||||
meta_item_name));
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> {
|
||||
let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit));
|
||||
syn::parse_path(&string).map_err(|err| cx.error(err))
|
||||
}
|
||||
|
||||
fn parse_lit_into_where(cx: &Ctxt,
|
||||
attr_name: &str,
|
||||
meta_item_name: &str,
|
||||
lit: &syn::Lit)
|
||||
-> Result<Vec<syn::WherePredicate>, ()> {
|
||||
let string = try!(get_string_from_lit(cx, attr_name, meta_item_name, lit));
|
||||
if string.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let where_string = format!("where {}", string);
|
||||
|
||||
syn::parse_where_clause(&where_string).map(|wh| wh.predicates).map_err(|err| cx.error(err))
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
extern crate syn;
|
||||
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use ctxt::Ctxt;
|
||||
+13
-9
@@ -1,27 +1,31 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "0.9.8"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
version = "1.0.60" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||
homepage = "https://serde.rs"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://serde.rs/codegen.html"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
readme = "../README.md"
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[features]
|
||||
unstable = []
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
deserialize_in_place = []
|
||||
|
||||
[lib]
|
||||
name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.3.8"
|
||||
serde_codegen_internals = { version = "=0.14.0", default-features = false, path = "../serde_codegen_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
proc-macro2 = "0.4"
|
||||
quote = "0.6"
|
||||
syn = { version = "0.14", features = ["visit"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
+241
-150
@@ -1,70 +1,90 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syn::{self, visit};
|
||||
use syn;
|
||||
use syn::punctuated::{Pair, Punctuated};
|
||||
use syn::visit::{self, Visit};
|
||||
|
||||
use internals::ast::Item;
|
||||
use internals::ast::{Container, Data};
|
||||
use internals::attr;
|
||||
|
||||
macro_rules! path {
|
||||
($first:ident $(:: $rest:ident)*) => {
|
||||
syn::Path {
|
||||
global: false,
|
||||
segments: vec![
|
||||
stringify!($first).into(),
|
||||
$(
|
||||
stringify!($rest).into(),
|
||||
)*
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
(::$first:ident $(:: $rest:ident)*) => {
|
||||
syn::Path {
|
||||
global: true,
|
||||
segments: vec![
|
||||
stringify!($first).into(),
|
||||
$(
|
||||
stringify!($rest).into(),
|
||||
)*
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
use proc_macro2::Span;
|
||||
|
||||
// Remove the default from every type parameter because in the generated impls
|
||||
// they look like associated types: "error: associated type bindings are not
|
||||
// allowed here".
|
||||
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
|
||||
syn::Generics {
|
||||
ty_params: generics.ty_params
|
||||
params: generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|ty_param| syn::TyParam { default: None, ..ty_param.clone() })
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam {
|
||||
eq_token: None,
|
||||
default: None,
|
||||
..param.clone()
|
||||
}),
|
||||
_ => param.clone(),
|
||||
})
|
||||
.collect(),
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_where_predicates(generics: &syn::Generics,
|
||||
predicates: &[syn::WherePredicate])
|
||||
-> syn::Generics {
|
||||
pub fn with_where_predicates(
|
||||
generics: &syn::Generics,
|
||||
predicates: &[syn::WherePredicate],
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend_from_slice(predicates);
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.extend(predicates.into_iter().cloned());
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_where_predicates_from_fields<F>(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
from_field: F)
|
||||
-> syn::Generics
|
||||
where F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>
|
||||
{
|
||||
let predicates = item.body
|
||||
pub fn with_where_predicates_from_fields(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
|
||||
) -> syn::Generics {
|
||||
let predicates = cont
|
||||
.data
|
||||
.all_fields()
|
||||
.flat_map(|field| from_field(&field.attrs))
|
||||
.flat_map(|predicates| predicates.to_vec());
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(predicates);
|
||||
generics.make_where_clause().predicates.extend(predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_where_predicates_from_variants(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
|
||||
) -> syn::Generics {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return generics.clone();
|
||||
}
|
||||
};
|
||||
|
||||
let predicates = variants
|
||||
.iter()
|
||||
.flat_map(|variant| from_variant(&variant.attrs))
|
||||
.flat_map(|predicates| predicates.to_vec());
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.make_where_clause().predicates.extend(predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
@@ -79,150 +99,221 @@ pub fn with_where_predicates_from_fields<F>(item: &Item,
|
||||
// #[serde(skip_serializing)]
|
||||
// c: C,
|
||||
// }
|
||||
pub fn with_bound<F>(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
filter: F,
|
||||
bound: &syn::Path)
|
||||
-> syn::Generics
|
||||
where F: Fn(&attr::Field) -> bool
|
||||
{
|
||||
struct FindTyParams {
|
||||
pub fn with_bound(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics {
|
||||
struct FindTyParams<'ast> {
|
||||
// Set of all generic type parameters on the current struct (A, B, C in
|
||||
// the example). Initialized up front.
|
||||
all_ty_params: HashSet<syn::Ident>,
|
||||
all_type_params: HashSet<syn::Ident>,
|
||||
|
||||
// Set of generic type parameters used in fields for which filter
|
||||
// returns true (A and B in the example). Filled in as the visitor sees
|
||||
// them.
|
||||
relevant_ty_params: HashSet<syn::Ident>,
|
||||
relevant_type_params: HashSet<syn::Ident>,
|
||||
|
||||
// Fields whose type is an associated type of one of the generic type
|
||||
// parameters.
|
||||
associated_type_usage: Vec<&'ast syn::TypePath>,
|
||||
}
|
||||
impl visit::Visitor for FindTyParams {
|
||||
fn visit_path(&mut self, path: &syn::Path) {
|
||||
impl<'ast> Visit<'ast> for FindTyParams<'ast> {
|
||||
fn visit_field(&mut self, field: &'ast syn::Field) {
|
||||
if let syn::Type::Path(ref ty) = field.ty {
|
||||
if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() {
|
||||
if self.all_type_params.contains(&t.ident) {
|
||||
self.associated_type_usage.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.visit_type(&field.ty);
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'ast syn::Path) {
|
||||
if let Some(seg) = path.segments.last() {
|
||||
if seg.ident == "PhantomData" {
|
||||
if seg.into_value().ident == "PhantomData" {
|
||||
// Hardcoded exception, because PhantomData<T> implements
|
||||
// Serialize and Deserialize whether or not T implements it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !path.global && path.segments.len() == 1 {
|
||||
let id = path.segments[0].ident.clone();
|
||||
if self.all_ty_params.contains(&id) {
|
||||
self.relevant_ty_params.insert(id);
|
||||
if path.leading_colon.is_none() && path.segments.len() == 1 {
|
||||
let id = &path.segments[0].ident;
|
||||
if self.all_type_params.contains(id) {
|
||||
self.relevant_type_params.insert(id.clone());
|
||||
}
|
||||
}
|
||||
visit::walk_path(self, path);
|
||||
visit::visit_path(self, path);
|
||||
}
|
||||
|
||||
// Type parameter should not be considered used by a macro path.
|
||||
//
|
||||
// struct TypeMacro<T> {
|
||||
// mac: T!(),
|
||||
// marker: PhantomData<T>,
|
||||
// }
|
||||
fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
|
||||
}
|
||||
|
||||
let all_type_params = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_type_params: all_type_params,
|
||||
relevant_type_params: HashSet::new(),
|
||||
associated_type_usage: Vec::new(),
|
||||
};
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => for variant in variants.iter() {
|
||||
let relevant_fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
|
||||
for field in relevant_fields {
|
||||
visitor.visit_field(field.original);
|
||||
}
|
||||
},
|
||||
Data::Struct(_, ref fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visitor.visit_field(field.original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let all_ty_params: HashSet<_> = generics.ty_params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let relevant_tys = item.body
|
||||
.all_fields()
|
||||
.filter(|&field| filter(&field.attrs))
|
||||
.map(|field| &field.ty);
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_ty_params: all_ty_params,
|
||||
relevant_ty_params: HashSet::new(),
|
||||
};
|
||||
for ty in relevant_tys {
|
||||
visit::walk_ty(&mut visitor, ty);
|
||||
}
|
||||
|
||||
let new_predicates = generics.ty_params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.filter(|id| visitor.relevant_ty_params.contains(id))
|
||||
.map(|id| {
|
||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
let relevant_type_params = visitor.relevant_type_params;
|
||||
let associated_type_usage = visitor.associated_type_usage;
|
||||
let new_predicates = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident.clone())
|
||||
.filter(|id| relevant_type_params.contains(id))
|
||||
.map(|id| syn::TypePath {
|
||||
qself: None,
|
||||
path: id.into(),
|
||||
})
|
||||
.chain(associated_type_usage.into_iter().cloned())
|
||||
.map(|bounded_ty| {
|
||||
syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type parameter that is being bounded e.g. T
|
||||
bounded_ty: syn::Ty::Path(None, id.into()),
|
||||
bounded_ty: syn::Type::Path(bounded_ty),
|
||||
colon_token: Default::default(),
|
||||
// the bound e.g. Serialize
|
||||
bounds: vec![syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None
|
||||
)],
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})].into_iter()
|
||||
.collect(),
|
||||
})
|
||||
});
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(new_predicates);
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.extend(new_predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_self_bound(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
bound: &syn::Path)
|
||||
-> syn::Generics
|
||||
{
|
||||
pub fn with_self_bound(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.push(
|
||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||
bounded_ty: type_of_item(item),
|
||||
bounded_ty: type_of_item(cont),
|
||||
colon_token: Default::default(),
|
||||
// the bound e.g. Default
|
||||
bounds: vec![syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None
|
||||
)],
|
||||
})
|
||||
);
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})].into_iter()
|
||||
.collect(),
|
||||
}));
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_lifetime_bound(generics: &syn::Generics,
|
||||
lifetime: &str)
|
||||
-> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
|
||||
for lifetime_def in &mut generics.lifetimes {
|
||||
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
|
||||
}
|
||||
|
||||
for ty_param in &mut generics.ty_params {
|
||||
ty_param.bounds.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
|
||||
}
|
||||
|
||||
generics.lifetimes.push(syn::LifetimeDef {
|
||||
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
|
||||
let bound = syn::Lifetime::new(lifetime, Span::call_site());
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(lifetime),
|
||||
bounds: Vec::new(),
|
||||
});
|
||||
lifetime: bound.clone(),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
|
||||
generics
|
||||
let params = Some(syn::GenericParam::Lifetime(def))
|
||||
.into_iter()
|
||||
.chain(generics.params.iter().cloned().map(|mut param| {
|
||||
match param {
|
||||
syn::GenericParam::Lifetime(ref mut param) => {
|
||||
param.bounds.push(bound.clone());
|
||||
}
|
||||
syn::GenericParam::Type(ref mut param) => {
|
||||
param
|
||||
.bounds
|
||||
.push(syn::TypeParamBound::Lifetime(bound.clone()));
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
param
|
||||
}))
|
||||
.collect();
|
||||
|
||||
syn::Generics {
|
||||
params: params,
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn type_of_item(item: &Item) -> syn::Ty {
|
||||
syn::Ty::Path(None, syn::Path {
|
||||
global: false,
|
||||
segments: vec![
|
||||
syn::PathSegment {
|
||||
ident: item.ident.clone(),
|
||||
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
|
||||
lifetimes: item.generics
|
||||
.lifetimes
|
||||
.iter()
|
||||
.map(|def| def.lifetime.clone())
|
||||
.collect(),
|
||||
types: item.generics
|
||||
.ty_params
|
||||
.iter()
|
||||
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
|
||||
.collect(),
|
||||
bindings: Vec::new(),
|
||||
}),
|
||||
}
|
||||
]
|
||||
fn type_of_item(cont: &Container) -> syn::Type {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments: vec![syn::PathSegment {
|
||||
ident: cont.ident.clone(),
|
||||
arguments: syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
lt_token: Default::default(),
|
||||
args: cont
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => {
|
||||
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: param.ident.clone().into(),
|
||||
}))
|
||||
}
|
||||
syn::GenericParam::Lifetime(ref param) => {
|
||||
syn::GenericArgument::Lifetime(param.lifetime.clone())
|
||||
}
|
||||
syn::GenericParam::Const(_) => {
|
||||
panic!("Serde does not support const generics yet");
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
gt_token: Default::default(),
|
||||
},
|
||||
),
|
||||
}].into_iter()
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+2227
-683
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,21 @@
|
||||
use quote::{Tokens, ToTokens};
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::token;
|
||||
|
||||
pub enum Fragment {
|
||||
/// Tokens that can be used as an expression.
|
||||
Expr(Tokens),
|
||||
Expr(TokenStream),
|
||||
/// Tokens that can be used inside a block. The surrounding curly braces are
|
||||
/// not part of these tokens.
|
||||
Block(Tokens),
|
||||
Block(TokenStream),
|
||||
}
|
||||
|
||||
macro_rules! quote_expr {
|
||||
@@ -24,13 +34,11 @@ macro_rules! quote_block {
|
||||
/// Block fragments in curly braces.
|
||||
pub struct Expr(pub Fragment);
|
||||
impl ToTokens for Expr {
|
||||
fn to_tokens(&self, out: &mut Tokens) {
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +47,7 @@ impl ToTokens for Expr {
|
||||
/// Interpolate a fragment as the statements of a block.
|
||||
pub struct Stmts(pub Fragment);
|
||||
impl ToTokens for Stmts {
|
||||
fn to_tokens(&self, out: &mut Tokens) {
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => block.to_tokens(out),
|
||||
@@ -51,17 +59,24 @@ impl ToTokens for Stmts {
|
||||
/// involves putting a comma after expressions and curly braces around blocks.
|
||||
pub struct Match(pub Fragment);
|
||||
impl ToTokens for Match {
|
||||
fn to_tokens(&self, out: &mut Tokens) {
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => {
|
||||
expr.to_tokens(out);
|
||||
out.append(",");
|
||||
<Token![,]>::default().to_tokens(out);
|
||||
}
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<TokenStream> for Fragment {
|
||||
fn as_ref(&self) -> &TokenStream {
|
||||
match *self {
|
||||
Fragment::Expr(ref expr) => expr,
|
||||
Fragment::Block(ref block) => block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use internals::attr;
|
||||
use internals::check;
|
||||
use internals::{Ctxt, Derive};
|
||||
use syn;
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
pub struct Container<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Container,
|
||||
pub data: Data<'a>,
|
||||
pub generics: &'a syn::Generics,
|
||||
}
|
||||
|
||||
pub enum Data<'a> {
|
||||
Enum(Vec<Variant<'a>>),
|
||||
Struct(Style, Vec<Field<'a>>),
|
||||
}
|
||||
|
||||
pub struct Variant<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Variant,
|
||||
pub style: Style,
|
||||
pub fields: Vec<Field<'a>>,
|
||||
}
|
||||
|
||||
pub struct Field<'a> {
|
||||
pub member: syn::Member,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Type,
|
||||
pub original: &'a syn::Field,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Style {
|
||||
Struct,
|
||||
Tuple,
|
||||
Newtype,
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a> Container<'a> {
|
||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Container<'a> {
|
||||
let mut attrs = attr::Container::from_ast(cx, item);
|
||||
|
||||
let mut data = match item.data {
|
||||
syn::Data::Enum(ref data) => {
|
||||
Data::Enum(enum_from_ast(cx, &data.variants, attrs.default()))
|
||||
}
|
||||
syn::Data::Struct(ref data) => {
|
||||
let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default());
|
||||
Data::Struct(style, fields)
|
||||
}
|
||||
syn::Data::Union(_) => {
|
||||
panic!("Serde does not support derive for unions");
|
||||
}
|
||||
};
|
||||
|
||||
let mut has_flatten = false;
|
||||
match data {
|
||||
Data::Enum(ref mut variants) => for variant in variants {
|
||||
variant.attrs.rename_by_rule(attrs.rename_all());
|
||||
for field in &mut variant.fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rule(variant.attrs.rename_all());
|
||||
}
|
||||
},
|
||||
Data::Struct(_, ref mut fields) => for field in fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rule(attrs.rename_all());
|
||||
},
|
||||
}
|
||||
|
||||
if has_flatten {
|
||||
attrs.mark_has_flatten();
|
||||
}
|
||||
|
||||
let mut item = Container {
|
||||
ident: item.ident.clone(),
|
||||
attrs: attrs,
|
||||
data: data,
|
||||
generics: &item.generics,
|
||||
};
|
||||
check::check(cx, &mut item, derive);
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Data<'a> {
|
||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
||||
match *self {
|
||||
Data::Enum(ref variants) => {
|
||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Data::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_getter(&self) -> bool {
|
||||
self.all_fields().any(|f| f.attrs.getter().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Variant<'a>> {
|
||||
variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs: attrs,
|
||||
style: style,
|
||||
fields: fields,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn struct_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a syn::Fields,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match *fields {
|
||||
syn::Fields::Named(ref fields) => (
|
||||
Style::Struct,
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(ref fields) => (
|
||||
Style::Tuple,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Field<'a>> {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| Field {
|
||||
member: match field.ident {
|
||||
Some(ref ident) => syn::Member::Named(ident.clone()),
|
||||
None => syn::Member::Unnamed(i.into()),
|
||||
},
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
|
||||
ty: &field.ty,
|
||||
original: field,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// 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::*;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum RenameRule {
|
||||
/// Don't apply a default rename rule.
|
||||
None,
|
||||
/// Rename direct children to "lowercase" style.
|
||||
LowerCase,
|
||||
/// Rename direct children to "UPPERCASE" style.
|
||||
UPPERCASE,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
|
||||
PascalCase,
|
||||
/// Rename direct children to "camelCase" style.
|
||||
CamelCase,
|
||||
/// Rename direct children to "snake_case" style, as commonly used for fields.
|
||||
SnakeCase,
|
||||
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly used for constants.
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
|
||||
ScreamingKebabCase,
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
LowerCase => variant.to_ascii_lowercase(),
|
||||
UPPERCASE => variant.to_ascii_uppercase(),
|
||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||
SnakeCase => {
|
||||
let mut snake = String::new();
|
||||
for (i, ch) in variant.char_indices() {
|
||||
if i > 0 && ch.is_uppercase() {
|
||||
snake.push('_');
|
||||
}
|
||||
snake.push(ch.to_ascii_lowercase());
|
||||
}
|
||||
snake
|
||||
}
|
||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase
|
||||
.apply_to_variant(variant)
|
||||
.replace('_', "-"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_to_field(&self, field: &str) -> String {
|
||||
match *self {
|
||||
None | LowerCase | SnakeCase => field.to_owned(),
|
||||
UPPERCASE => field.to_ascii_uppercase(),
|
||||
PascalCase => {
|
||||
let mut pascal = String::new();
|
||||
let mut capitalize = true;
|
||||
for ch in field.chars() {
|
||||
if ch == '_' {
|
||||
capitalize = true;
|
||||
} else if capitalize {
|
||||
pascal.push(ch.to_ascii_uppercase());
|
||||
capitalize = false;
|
||||
} else {
|
||||
pascal.push(ch);
|
||||
}
|
||||
}
|
||||
pascal
|
||||
}
|
||||
CamelCase => {
|
||||
let pascal = PascalCase.apply_to_field(field);
|
||||
pascal[..1].to_ascii_lowercase() + &pascal[1..]
|
||||
}
|
||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||
KebabCase => field.replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RenameRule {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
||||
match rename_all_str {
|
||||
"lowercase" => Ok(LowerCase),
|
||||
"UPPERCASE" => Ok(UPPERCASE),
|
||||
"PascalCase" => Ok(PascalCase),
|
||||
"camelCase" => Ok(CamelCase),
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||
"kebab-case" => Ok(KebabCase),
|
||||
"SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||
),
|
||||
(
|
||||
"VeryTasty",
|
||||
"verytasty",
|
||||
"VERYTASTY",
|
||||
"veryTasty",
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("A", "a", "A", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
assert_eq!(UPPERCASE.apply_to_variant(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||
assert_eq!(
|
||||
ScreamingKebabCase.apply_to_variant(original),
|
||||
screaming_kebab
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||
),
|
||||
(
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"VeryTasty",
|
||||
"veryTasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("a", "A", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(UPPERCASE.apply_to_field(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use internals::ast::{Container, Data, Field, Style};
|
||||
use internals::attr::{EnumTag, Identifier};
|
||||
use internals::{Ctxt, Derive};
|
||||
use syn::{Member, Type};
|
||||
|
||||
/// Cross-cutting checks that require looking at more than a single attrs
|
||||
/// object. Simpler checks should happen when parsing and building the attrs.
|
||||
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
||||
check_getter(cx, cont);
|
||||
check_flatten(cx, cont);
|
||||
check_identifier(cx, cont);
|
||||
check_variant_skip_attrs(cx, cont);
|
||||
check_internal_tag_field_name_conflict(cx, cont);
|
||||
check_adjacent_tag_conflict(cx, cont);
|
||||
check_transparent(cx, cont, derive);
|
||||
}
|
||||
|
||||
/// Getters are only allowed inside structs (not enums) with the `remote`
|
||||
/// attribute.
|
||||
fn check_getter(cx: &Ctxt, cont: &Container) {
|
||||
match cont.data {
|
||||
Data::Enum(_) => {
|
||||
if cont.data.has_getter() {
|
||||
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
|
||||
}
|
||||
}
|
||||
Data::Struct(_, _) => {
|
||||
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
||||
cx.error(
|
||||
"#[serde(getter = \"...\")] can only be used in structs \
|
||||
that have #[serde(remote = \"...\")]",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Flattening has some restrictions we can test.
|
||||
fn check_flatten(cx: &Ctxt, cont: &Container) {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => {
|
||||
for variant in variants {
|
||||
for field in &variant.fields {
|
||||
check_flatten_field(cx, variant.style, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Struct(style, ref fields) => {
|
||||
for field in fields {
|
||||
check_flatten_field(cx, style, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
|
||||
if !field.attrs.flatten() {
|
||||
return;
|
||||
}
|
||||
match style {
|
||||
Style::Tuple => {
|
||||
cx.error("#[serde(flatten)] cannot be used on tuple structs");
|
||||
}
|
||||
Style::Newtype => {
|
||||
cx.error("#[serde(flatten)] cannot be used on newtype structs");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if field.attrs.skip_serializing() {
|
||||
cx.error(
|
||||
"#[serde(flatten] can not be combined with \
|
||||
#[serde(skip_serializing)]",
|
||||
);
|
||||
} else if field.attrs.skip_serializing_if().is_some() {
|
||||
cx.error(
|
||||
"#[serde(flatten] can not be combined with \
|
||||
#[serde(skip_serializing_if = \"...\")]",
|
||||
);
|
||||
} else if field.attrs.skip_deserializing() {
|
||||
cx.error(
|
||||
"#[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
|
||||
/// variant of an enum that has the `field_identifier` attribute.
|
||||
///
|
||||
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
|
||||
/// `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.
|
||||
fn check_identifier(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for (i, variant) in variants.iter().enumerate() {
|
||||
match (
|
||||
variant.style,
|
||||
cont.attrs.identifier(),
|
||||
variant.attrs.other(),
|
||||
) {
|
||||
// The `other` attribute may only be used in a field_identifier.
|
||||
(_, Identifier::Variant, true) | (_, Identifier::No, true) => {
|
||||
cx.error("#[serde(other)] may only be used inside a field_identifier");
|
||||
}
|
||||
|
||||
// Variant with `other` attribute must be the last one.
|
||||
(Style::Unit, Identifier::Field, true) => {
|
||||
if i < variants.len() - 1 {
|
||||
cx.error("#[serde(other)] must be the last variant");
|
||||
}
|
||||
}
|
||||
|
||||
// Variant with `other` attribute must be a unit variant.
|
||||
(_, Identifier::Field, true) => {
|
||||
cx.error("#[serde(other)] must be on a unit variant");
|
||||
}
|
||||
|
||||
// Any sort of variant is allowed if this is not an identifier.
|
||||
(_, Identifier::No, false) => {}
|
||||
|
||||
// Unit variant without `other` attribute is always fine.
|
||||
(Style::Unit, _, false) => {}
|
||||
|
||||
// The last field is allowed to be a newtype catch-all.
|
||||
(Style::Newtype, Identifier::Field, false) => {
|
||||
if i < variants.len() - 1 {
|
||||
cx.error(format!("`{}` must be the last variant", variant.ident));
|
||||
}
|
||||
}
|
||||
|
||||
(_, Identifier::Field, false) => {
|
||||
cx.error("field_identifier may only contain unit variants");
|
||||
}
|
||||
|
||||
(_, Identifier::Variant, false) => {
|
||||
cx.error("variant_identifier may only contain unit variants");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skip-(de)serializing attributes are not allowed on variants marked
|
||||
/// (de)serialize_with.
|
||||
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for variant in variants.iter() {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
if variant.attrs.skip_serializing() {
|
||||
cx.error(format!(
|
||||
"variant `{}` cannot have both #[serde(serialize_with)] and \
|
||||
#[serde(skip_serializing)]",
|
||||
variant.ident
|
||||
));
|
||||
}
|
||||
|
||||
for field in &variant.fields {
|
||||
let member = member_message(&field.member);
|
||||
|
||||
if field.attrs.skip_serializing() {
|
||||
cx.error(format!(
|
||||
"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() {
|
||||
cx.error(format!(
|
||||
"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.skip_deserializing() {
|
||||
cx.error(format!(
|
||||
"variant `{}` cannot have both #[serde(deserialize_with)] and \
|
||||
#[serde(skip_deserializing)]",
|
||||
variant.ident
|
||||
));
|
||||
}
|
||||
|
||||
for field in &variant.fields {
|
||||
if field.attrs.skip_deserializing() {
|
||||
let member = member_message(&field.member);
|
||||
|
||||
cx.error(format!(
|
||||
"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 same as either one of its fields, as this would result in
|
||||
/// duplicate keys in the serialized output and/or ambiguity in
|
||||
/// the to-be-deserialized input.
|
||||
fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => return,
|
||||
};
|
||||
|
||||
let tag = match *cont.attrs.tag() {
|
||||
EnumTag::Internal { ref tag } => tag.as_str(),
|
||||
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
|
||||
};
|
||||
|
||||
let diagnose_conflict = || {
|
||||
let message = format!("variant field name `{}` conflicts with internal tag", tag);
|
||||
cx.error(message);
|
||||
};
|
||||
|
||||
for variant in variants {
|
||||
match variant.style {
|
||||
Style::Struct => {
|
||||
for field in &variant.fields {
|
||||
let check_ser = !field.attrs.skip_serializing();
|
||||
let check_de = !field.attrs.skip_deserializing();
|
||||
let name = field.attrs.name();
|
||||
let ser_name = name.serialize_name();
|
||||
let de_name = name.deserialize_name();
|
||||
|
||||
if check_ser && ser_name == tag || check_de && de_name == tag {
|
||||
diagnose_conflict();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Style::Unit | Style::Newtype | Style::Tuple => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In the case of adjacently-tagged enums, the type and the
|
||||
/// contents tag must differ, for the same reason.
|
||||
fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
|
||||
let (type_tag, content_tag) = match *cont.attrs.tag() {
|
||||
EnumTag::Adjacent {
|
||||
ref tag,
|
||||
ref content,
|
||||
} => (tag, content),
|
||||
EnumTag::Internal { .. } | EnumTag::External | EnumTag::None => return,
|
||||
};
|
||||
|
||||
if type_tag == content_tag {
|
||||
let message = format!(
|
||||
"enum tags `{}` for type and content conflict with each other",
|
||||
type_tag
|
||||
);
|
||||
cx.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// Enums and unit structs cannot be transparent.
|
||||
fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
||||
if !cont.attrs.transparent() {
|
||||
return;
|
||||
}
|
||||
|
||||
if cont.attrs.type_from().is_some() {
|
||||
cx.error("#[serde(transparent)] is not allowed with #[serde(from = \"...\")]");
|
||||
}
|
||||
|
||||
if cont.attrs.type_into().is_some() {
|
||||
cx.error("#[serde(transparent)] is not allowed with #[serde(into = \"...\")]");
|
||||
}
|
||||
|
||||
let fields = match cont.data {
|
||||
Data::Enum(_) => {
|
||||
cx.error("#[serde(transparent)] is not allowed on an enum");
|
||||
return;
|
||||
}
|
||||
Data::Struct(Style::Unit, _) => {
|
||||
cx.error("#[serde(transparent)] is not allowed on a unit struct");
|
||||
return;
|
||||
}
|
||||
Data::Struct(_, ref mut fields) => fields,
|
||||
};
|
||||
|
||||
let mut transparent_field = None;
|
||||
|
||||
for field in fields {
|
||||
if allow_transparent(field, derive) {
|
||||
if transparent_field.is_some() {
|
||||
cx.error(
|
||||
"#[serde(transparent)] requires struct to have at most one transparent field",
|
||||
);
|
||||
return;
|
||||
}
|
||||
transparent_field = Some(field);
|
||||
}
|
||||
}
|
||||
|
||||
match transparent_field {
|
||||
Some(transparent_field) => transparent_field.attrs.mark_transparent(),
|
||||
None => match derive {
|
||||
Derive::Serialize => {
|
||||
cx.error("#[serde(transparent)] requires at least one field that is not skipped");
|
||||
}
|
||||
Derive::Deserialize => {
|
||||
cx.error("#[serde(transparent)] requires at least one field that is neither skipped nor has a default");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn member_message(member: &Member) -> String {
|
||||
match *member {
|
||||
Member::Named(ref ident) => format!("`{}`", ident),
|
||||
Member::Unnamed(ref i) => i.index.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn allow_transparent(field: &Field, derive: Derive) -> bool {
|
||||
if let Type::Path(ref ty) = *field.ty {
|
||||
if let Some(seg) = ty.path.segments.last() {
|
||||
if seg.into_value().ident == "PhantomData" {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match derive {
|
||||
Derive::Serialize => !field.attrs.skip_serializing(),
|
||||
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
use std::fmt::Display;
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::thread;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Ctxt {
|
||||
@@ -8,11 +17,17 @@ pub struct Ctxt {
|
||||
|
||||
impl Ctxt {
|
||||
pub fn new() -> Self {
|
||||
Ctxt { errors: RefCell::new(Some(Vec::new())) }
|
||||
Ctxt {
|
||||
errors: RefCell::new(Some(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error<T: Display>(&self, msg: T) {
|
||||
self.errors.borrow_mut().as_mut().unwrap().push(msg.to_string());
|
||||
self.errors
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.push(msg.to_string());
|
||||
}
|
||||
|
||||
pub fn check(self) -> Result<(), String> {
|
||||
@@ -34,7 +49,7 @@ impl Ctxt {
|
||||
|
||||
impl Drop for Ctxt {
|
||||
fn drop(&mut self) {
|
||||
if self.errors.borrow().is_some() {
|
||||
if !thread::panicking() && self.errors.borrow().is_some() {
|
||||
panic!("forgot to check for errors");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use self::ctxt::Ctxt;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Derive {
|
||||
Serialize,
|
||||
Deserialize,
|
||||
}
|
||||
+56
-11
@@ -1,40 +1,85 @@
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This crate provides Serde's two derive macros.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #[macro_use]
|
||||
//! # extern crate serde_derive;
|
||||
//! #
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! # struct S;
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.60")]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
enum_variant_names, redundant_field_names, too_many_arguments, used_underscore_binding,
|
||||
cyclomatic_complexity
|
||||
)
|
||||
)]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
items_after_statements, doc_markdown, stutter, similar_names, use_self, single_match_else,
|
||||
enum_glob_use, match_same_arms, filter_map, cast_possible_truncation
|
||||
)
|
||||
)]
|
||||
// The `quote!` macro requires deep recursion.
|
||||
#![recursion_limit = "192"]
|
||||
#![recursion_limit = "512"]
|
||||
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
extern crate serde_codegen_internals as internals;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
|
||||
mod internals;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::DeriveInput;
|
||||
|
||||
#[macro_use]
|
||||
mod bound;
|
||||
#[macro_use]
|
||||
mod fragment;
|
||||
|
||||
mod ser;
|
||||
mod de;
|
||||
mod pretend;
|
||||
mod ser;
|
||||
mod try;
|
||||
|
||||
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match ser::expand_derive_serialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Deserialize, attributes(serde))]
|
||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match de::expand_derive_deserialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use syn::Ident;
|
||||
|
||||
use internals::ast::{Container, Data, Field, Style};
|
||||
|
||||
// Suppress dead_code warnings that would otherwise appear when using a remote
|
||||
// derive. Other than this pretend code, a struct annotated with remote derive
|
||||
// never has its fields referenced and an enum annotated with remote derive
|
||||
// never has its variants constructed.
|
||||
//
|
||||
// warning: field is never used: `i`
|
||||
// --> src/main.rs:4:20
|
||||
// |
|
||||
// 4 | struct StructDef { i: i32 }
|
||||
// | ^^^^^^
|
||||
//
|
||||
// warning: variant is never constructed: `V`
|
||||
// --> src/main.rs:8:16
|
||||
// |
|
||||
// 8 | enum EnumDef { V }
|
||||
// | ^
|
||||
//
|
||||
pub fn pretend_used(cont: &Container) -> TokenStream {
|
||||
let pretend_fields = pretend_fields_used(cont);
|
||||
let pretend_variants = pretend_variants_used(cont);
|
||||
|
||||
quote! {
|
||||
#pretend_fields
|
||||
#pretend_variants
|
||||
}
|
||||
}
|
||||
|
||||
// For structs with named fields, expands to:
|
||||
//
|
||||
// match None::<T> {
|
||||
// Some(T { a: ref __v0, b: ref __v1 }) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
// For enums, expands to the following but only including struct variants:
|
||||
//
|
||||
// match None::<T> {
|
||||
// Some(T::A { a: ref __v0 }) => {}
|
||||
// Some(T::B { b: ref __v0 }) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
// The `ref` is important in case the user has written a Drop impl on their
|
||||
// type. Rust does not allow destructuring a struct or enum that has a Drop
|
||||
// impl.
|
||||
fn pretend_fields_used(cont: &Container) -> TokenStream {
|
||||
let type_ident = &cont.ident;
|
||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||
|
||||
let patterns = match cont.data {
|
||||
Data::Enum(ref variants) => variants
|
||||
.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! {
|
||||
match _serde::export::None::<#type_ident #ty_generics> {
|
||||
#(
|
||||
_serde::export::Some(#patterns) => {}
|
||||
)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expands to one of these per enum variant:
|
||||
//
|
||||
// match None {
|
||||
// Some((__v0, __v1,)) => {
|
||||
// let _ = E::V { a: __v0, b: __v1 };
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
fn pretend_variants_used(cont: &Container) -> TokenStream {
|
||||
let variants = match cont.data {
|
||||
Data::Enum(ref variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return quote!();
|
||||
}
|
||||
};
|
||||
|
||||
let type_ident = &cont.ident;
|
||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||
let turbofish = ty_generics.as_turbofish();
|
||||
|
||||
let cases = variants.iter().map(|variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
let placeholders = &(0..variant.fields.len())
|
||||
.map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pat = match variant.style {
|
||||
Style::Struct => {
|
||||
let members = variant.fields.iter().map(|field| &field.member);
|
||||
quote!({ #(#members: #placeholders),* })
|
||||
}
|
||||
Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
|
||||
Style::Unit => quote!(),
|
||||
};
|
||||
|
||||
quote! {
|
||||
match _serde::export::None {
|
||||
_serde::export::Some((#(#placeholders,)*)) => {
|
||||
let _ = #type_ident::#variant_ident #turbofish #pat;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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),* })
|
||||
}
|
||||
+883
-382
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.23.1" # remember to update html_root_url
|
||||
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."
|
||||
homepage = "https://serde.rs"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://docs.serde.rs/serde_derive_internals/"
|
||||
keywords = ["serde", "serialization"]
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "lib.rs", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "0.4"
|
||||
syn = { version = "0.14", default-features = false, features = ["derive", "parsing", "clone-impls"] }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.23.1")]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(cyclomatic_complexity, doc_markdown, match_same_arms, redundant_field_names)
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro2;
|
||||
|
||||
#[path = "src/mod.rs"]
|
||||
mod internals;
|
||||
|
||||
pub use internals::*;
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../serde_derive/src/internals/
|
||||
@@ -1,18 +1,22 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "0.9.8"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
version = "1.0.60" # 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 = "../README.md"
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "0.9", path = "../serde" }
|
||||
serde = { version = "1.0.16", path = "../serde" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0.16", path = "../serde", features = ["rc"] }
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
|
||||
+232
-29
@@ -1,54 +1,257 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use de::Deserializer;
|
||||
use error::Error;
|
||||
use ser::Serializer;
|
||||
use token::Token;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub fn assert_tokens<T>(value: &T, tokens: &[Token<'static>])
|
||||
where T: Serialize + Deserialize + PartialEq + 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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new(tokens.iter());
|
||||
assert_eq!(Serialize::serialize(value, &mut ser), Ok(()));
|
||||
assert_eq!(ser.next_token(), None);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// Expect an error serializing `T`.
|
||||
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
|
||||
where T: Serialize + PartialEq + Debug
|
||||
/// 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.iter());
|
||||
let v: Result<(), Error> = Serialize::serialize(value, &mut ser);
|
||||
assert_eq!(v.as_ref(), Err(&error));
|
||||
assert_eq!(ser.next_token(), None);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
|
||||
where T: Deserialize + PartialEq + Debug
|
||||
/// 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.to_vec().into_iter());
|
||||
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
|
||||
assert_eq!(v.as_ref(), Ok(value));
|
||||
assert_eq!(de.next_token(), None);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// Expect an error deserializing tokens into a `T`.
|
||||
pub fn assert_de_tokens_error<T>(tokens: &[Token<'static>], error: Error)
|
||||
where T: Deserialize + PartialEq + Debug
|
||||
/// 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.to_vec().into_iter());
|
||||
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
|
||||
assert_eq!(v, Err(error));
|
||||
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();
|
||||
assert_eq!(de.next_token(), None);
|
||||
de.next_token_opt();
|
||||
|
||||
if de.remaining() > 0 {
|
||||
panic!("{} remaining tokens", de.remaining());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,844 @@
|
||||
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::{Configure, Token, assert_tokens};
|
||||
///
|
||||
/// #[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);
|
||||
+474
-353
File diff suppressed because it is too large
Load Diff
+28
-25
@@ -1,48 +1,51 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::error;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use serde::{ser, de};
|
||||
use serde::{de, ser};
|
||||
|
||||
use token::Token;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Error {
|
||||
Message(String),
|
||||
InvalidName(&'static str),
|
||||
UnexpectedToken(Token<'static>),
|
||||
EndOfTokens,
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Error {
|
||||
msg: String,
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Error {
|
||||
Error::Message(msg.to_string())
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error {
|
||||
msg: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Error {
|
||||
Error::Message(msg.to_string())
|
||||
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 {
|
||||
match *self {
|
||||
Error::Message(ref msg) => formatter.write_str(msg),
|
||||
Error::InvalidName(name) => write!(formatter, "invalid name `{}`", name),
|
||||
Error::UnexpectedToken(_) => formatter.write_str("unexpected token"),
|
||||
Error::EndOfTokens => formatter.write_str("end of tokens"),
|
||||
}
|
||||
formatter.write_str(&self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Message(ref msg) => msg,
|
||||
Error::InvalidName(_) => "invalid name",
|
||||
Error::UnexpectedToken(_) => "unexpected token",
|
||||
Error::EndOfTokens => "end of tokens",
|
||||
}
|
||||
&self.msg
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Error {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.msg == other
|
||||
}
|
||||
}
|
||||
|
||||
+190
-10
@@ -1,18 +1,198 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! 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.60")]
|
||||
#![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 assert;
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
|
||||
assert_de_tokens_error};
|
||||
|
||||
mod ser;
|
||||
pub use ser::Serializer;
|
||||
|
||||
mod de;
|
||||
pub use de::Deserializer;
|
||||
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;
|
||||
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
pub use configure::{Compact, Configure, Readable};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub use de::Deserializer;
|
||||
|
||||
+249
-141
@@ -1,363 +1,471 @@
|
||||
use std::marker::PhantomData;
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use serde::{ser, Serialize};
|
||||
|
||||
use error::Error;
|
||||
use token::Token;
|
||||
|
||||
pub struct Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
tokens: I,
|
||||
phantom: PhantomData<&'a Token<'a>>,
|
||||
/// 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, I> Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
pub fn new(tokens: I) -> Serializer<'a, I> {
|
||||
Serializer {
|
||||
tokens: tokens,
|
||||
phantom: PhantomData,
|
||||
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 next_token(&mut self) -> Option<&'a Token<'a>> {
|
||||
self.tokens.next()
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.tokens.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::Serializer for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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 = Self;
|
||||
type SerializeTupleVariant = Variant<'s, 'a>;
|
||||
type SerializeMap = Self;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStructVariant = Self;
|
||||
type SerializeStructVariant = Variant<'s, 'a>;
|
||||
|
||||
fn serialize_bool(self, v: bool) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Bool(v)));
|
||||
assert_next_token!(self, Bool(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I8(v)));
|
||||
assert_next_token!(self, I8(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I16(v)));
|
||||
assert_next_token!(self, I16(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I32(v)));
|
||||
assert_next_token!(self, I32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I64(v)));
|
||||
assert_next_token!(self, I64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U8(v)));
|
||||
assert_next_token!(self, U8(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U16(v)));
|
||||
assert_next_token!(self, U16(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U32(v)));
|
||||
assert_next_token!(self, U32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U64(v)));
|
||||
assert_next_token!(self, U64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::F32(v)));
|
||||
assert_next_token!(self, F32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::F64(v)));
|
||||
assert_next_token!(self, F64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Char(v)));
|
||||
assert_next_token!(self, Char(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Str(v)));
|
||||
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, value: &[u8]) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Bytes(value)));
|
||||
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_eq!(self.tokens.next(), Some(&Token::Unit));
|
||||
assert_next_token!(self, Unit);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, name: &str) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::UnitStruct(name)));
|
||||
fn serialize_unit_struct(self, name: &'static str) -> Result<(), Error> {
|
||||
assert_next_token!(self, UnitStruct { name });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str)
|
||||
-> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumUnit(name, variant)));
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructNewType(name)));
|
||||
assert_next_token!(self, NewtypeStruct { name });
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
value: &T)
|
||||
-> Result<(), Error>
|
||||
where T: Serialize
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant)));
|
||||
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_eq!(self.tokens.next(), Some(&Token::Option(false)));
|
||||
assert_next_token!(self, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Option(true)));
|
||||
assert_next_token!(self, Some);
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqStart(len)));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_seq_fixed_size(self, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqArrayStart(len)));
|
||||
assert_next_token!(self, Seq { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStart(len)));
|
||||
assert_next_token!(self, Tuple { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::TupleStructStart(name, len)));
|
||||
assert_next_token!(self, TupleStruct { name, len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
len: usize)
|
||||
-> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::EnumSeqStart(name, variant, 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_eq!(self.tokens.next(), Some(&Token::MapStart(len)));
|
||||
assert_next_token!(self, Map { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_struct(self, name: &str, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len)));
|
||||
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: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
len: usize)
|
||||
-> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::EnumMapStart(name, variant, 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`"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeSeq for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqEnd));
|
||||
assert_next_token!(self, SeqEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTuple for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleEnd));
|
||||
assert_next_token!(self, TupleEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTupleStruct for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStructSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStructEnd));
|
||||
assert_next_token!(self, TupleStructEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTupleVariant for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
|
||||
value.serialize(&mut **self)
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd));
|
||||
match self.end {
|
||||
Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd),
|
||||
Token::SeqEnd => assert_next_token!(self.ser, SeqEnd),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeMap for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
|
||||
key.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapEnd));
|
||||
assert_next_token!(self, MapEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeStruct for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructSep));
|
||||
try!(key.serialize(&mut **self));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructEnd));
|
||||
assert_next_token!(self, StructEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeStructVariant for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
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
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
|
||||
try!(key.serialize(&mut **self));
|
||||
value.serialize(&mut **self)
|
||||
try!(key.serialize(&mut *self.ser));
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapEnd));
|
||||
match self.end {
|
||||
Token::StructVariantEnd => assert_next_token!(self.ser, StructVariantEnd),
|
||||
Token::MapEnd => assert_next_token!(self.ser, MapEnd),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+542
-29
@@ -1,59 +1,572 @@
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Token<'a> {
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
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),
|
||||
Str(&'a str),
|
||||
String(String),
|
||||
Bytes(&'a [u8]),
|
||||
ByteBuf(Vec<u8>),
|
||||
|
||||
Option(bool),
|
||||
/// 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,
|
||||
UnitStruct(&'a str),
|
||||
|
||||
StructNewType(&'a str),
|
||||
/// 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 },
|
||||
|
||||
EnumStart(&'a str),
|
||||
EnumUnit(&'a str, &'a str),
|
||||
EnumNewType(&'a str, &'a 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,
|
||||
},
|
||||
|
||||
SeqStart(Option<usize>),
|
||||
SeqArrayStart(usize),
|
||||
SeqSep,
|
||||
/// 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,
|
||||
|
||||
TupleStart(usize),
|
||||
TupleSep,
|
||||
/// 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,
|
||||
|
||||
TupleStructStart(&'a str, usize),
|
||||
TupleStructSep,
|
||||
/// 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,
|
||||
|
||||
MapStart(Option<usize>),
|
||||
MapSep,
|
||||
/// 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,
|
||||
|
||||
StructStart(&'a str, usize),
|
||||
StructSep,
|
||||
/// 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,
|
||||
|
||||
EnumSeqStart(&'a str, &'a str, usize),
|
||||
EnumSeqSep,
|
||||
EnumSeqEnd,
|
||||
/// 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,
|
||||
},
|
||||
|
||||
EnumMapStart(&'a str, &'a str, usize),
|
||||
EnumMapSep,
|
||||
EnumMapEnd,
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-12
@@ -1,25 +1,19 @@
|
||||
[package]
|
||||
name = "serde_test_suite"
|
||||
version = "0.0.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
unstable-testing = [
|
||||
"compiletest_rs",
|
||||
"serde/unstable-testing",
|
||||
]
|
||||
unstable = ["serde/unstable", "compiletest_rs"]
|
||||
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
proc-macro2 = "0.4"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde" }
|
||||
serde_derive = { path = "../serde_derive" }
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||
serde_test = { path = "../serde_test" }
|
||||
|
||||
[dependencies]
|
||||
compiletest_rs = { version = "0.2", optional = true }
|
||||
|
||||
[[test]]
|
||||
name = "test"
|
||||
path = "tests/test.rs"
|
||||
compiletest_rs = { version = "0.3", optional = true }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(/*=============================================]
|
||||
#![=== Serde test suite requires a nightly compiler. ===]
|
||||
#![====================================================*/)]
|
||||
|
||||
@@ -4,5 +4,8 @@ version = "0.0.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2", default-features = false }
|
||||
serde = { path = "../../serde", default-features = false }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
#![feature(lang_items, start, libc)]
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(lang_items, start)]
|
||||
#![no_std]
|
||||
|
||||
extern crate libc;
|
||||
@@ -10,19 +18,17 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {}
|
||||
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {}
|
||||
pub extern "C" fn rust_eh_personality() {}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
pub extern "C" fn rust_begin_panic(
|
||||
_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32,
|
||||
) -> ! {
|
||||
unsafe {
|
||||
libc::abort()
|
||||
libc::abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +47,9 @@ struct Newtype(u8);
|
||||
struct Tuple(u8, u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Struct { f: u8 }
|
||||
struct Struct {
|
||||
f: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum Enum {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use serde::de::{Deserializer, Error, SeqAccess, Visitor};
|
||||
use std::fmt;
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_byte_buf(ByteBufVisitor)
|
||||
}
|
||||
|
||||
struct ByteBufVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ByteBufVisitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let mut values = Vec::new();
|
||||
while let Some(value) = try!(visitor.next_element()) {
|
||||
values.push(value);
|
||||
}
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(v.to_vec())
|
||||
}
|
||||
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(v.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(v.into_bytes())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct Test<'a> {
|
||||
#[serde(borrow = "zzz")] //~^^ HELP: failed to parse borrowed lifetimes: "zzz"
|
||||
s: &'a str,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct Test<'a> {
|
||||
#[serde(borrow = "'a + 'a")] //~^^ HELP: duplicate borrowed lifetime `'a`
|
||||
s: &'a str,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Str<'a>(&'a str);
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
enum Test<'a> {
|
||||
#[serde(borrow)] //~^^ HELP: duplicate serde attribute `borrow`
|
||||
S(#[serde(borrow)] Str<'a>)
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct Test<'a> {
|
||||
#[serde(borrow = "")] //~^^ HELP: at least one lifetime must be borrowed
|
||||
s: &'a str,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct Test {
|
||||
#[serde(borrow)] //~^^ HELP: field `s` has no lifetimes to borrow
|
||||
s: String,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Str<'a>(&'a str);
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
enum Test<'a> {
|
||||
#[serde(borrow)] //~^^ HELP: #[serde(borrow)] may only be used on newtype variants
|
||||
S { s: Str<'a> }
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct Test<'a> {
|
||||
#[serde(borrow = "'b")] //~^^ HELP: field `s` does not have lifetime 'b
|
||||
s: &'a str,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
#[serde(tag = "conflict", content = "conflict")]
|
||||
//~^^ HELP: enum tags `conflict` for type and content conflict with each other
|
||||
enum E {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: #[serde(flatten)] cannot be used on newtype structs
|
||||
struct Foo(#[serde(flatten)] HashMap<String, String>);
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Deserialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_deserializing)]
|
||||
struct Foo {
|
||||
#[serde(flatten, skip_deserializing)]
|
||||
other: Other,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Other {
|
||||
x: u32
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")]
|
||||
struct Foo {
|
||||
#[serde(flatten, skip_serializing_if="Option::is_none")]
|
||||
other: Option<Other>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Other {
|
||||
x: u32
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: #[serde(flatten] can not be combined with #[serde(skip_serializing)]
|
||||
struct Foo {
|
||||
#[serde(flatten, skip_serializing)]
|
||||
other: Other,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Other {
|
||||
x: u32
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
//~^ HELP: #[serde(flatten)] cannot be used on tuple structs
|
||||
struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2018 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
#[derive(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
#[serde(tag = "conflict")]
|
||||
//~^^ HELP: variant field name `conflict` conflicts with internal tag
|
||||
enum E {
|
||||
A {
|
||||
#[serde(rename = "conflict")]
|
||||
x: (),
|
||||
},
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// Copyright 2017 Serde Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user