mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 21:48:02 +00:00
Compare commits
724 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b539cb45d7 | |||
| a5490e20e1 | |||
| 45c45e87bf | |||
| 2e76f7013f | |||
| d35de19120 | |||
| e5b3507145 | |||
| 7ea7c2ceb9 | |||
| 2b5b15967e | |||
| 2ef60b62ac | |||
| e6f086d85e | |||
| bf76f50294 | |||
| ba07075590 | |||
| 26186bddd1 | |||
| 53b9871b17 | |||
| f8787c3ca8 | |||
| 3022064f84 | |||
| 9e140a2071 | |||
| 24e6acbfae | |||
| 29c5a50935 | |||
| c619b2a7c4 | |||
| 764ebd9b17 | |||
| 9c6f0c3a0e | |||
| a9f8ea0a1e | |||
| 04faac962a | |||
| 7e5701ad2b | |||
| 1cd10a7d09 | |||
| d5e6436b28 | |||
| 8ff11dc234 | |||
| 6b3777b617 | |||
| 7350b58f5c | |||
| 7351e0e55a | |||
| b3ff7e43ef | |||
| a50e1c20e9 | |||
| 6980727d74 | |||
| bb1dedf04d | |||
| f3520e526b | |||
| e8fd2c85c3 | |||
| 97962d51e2 | |||
| 95b1a5d3d9 | |||
| 0856a2c101 | |||
| 9f331cc257 | |||
| ef16c815f6 | |||
| c45a809d5c | |||
| f7d06cae4c | |||
| 31fe82a215 | |||
| ef6ed1d1be | |||
| 9d1251548b | |||
| c20730ee39 | |||
| afd51ef0f4 | |||
| 3167f98689 | |||
| 078b171c1b | |||
| da8d6f678e | |||
| 548eb8f667 | |||
| 1fe39043ee | |||
| c2114491ca | |||
| 9f47c47cad | |||
| d6b39fd2c1 | |||
| 4d6d0ae539 | |||
| dda070f45c | |||
| b97a183e82 | |||
| 9433004307 | |||
| 9476838264 | |||
| 172edc4cf4 | |||
| 3c97e1b9a9 | |||
| a81968af3c | |||
| ea2789df0f | |||
| b7cfe33101 | |||
| 1b8ebf6b64 | |||
| 35ad468780 | |||
| 850a29beb1 | |||
| 16bf9871cd | |||
| 6182eceed1 | |||
| 99bc52f685 | |||
| 726ff5ed31 | |||
| f63acb52dc | |||
| 36a66873cc | |||
| 63809e69c7 | |||
| f44402e224 | |||
| 099fa25b86 | |||
| c120c4518b | |||
| 115c1b4830 | |||
| 23db3a41e7 | |||
| e2ff603587 | |||
| 19a11237b8 | |||
| 732544aed6 | |||
| 65dfa607c8 | |||
| 59104bbc24 | |||
| 38ad09aeb7 | |||
| 02631cef42 | |||
| f369707dc5 | |||
| e16e924c21 | |||
| 8b52ddd5b9 | |||
| 112f2040ea | |||
| cd836eb3ca | |||
| 2b4355724e | |||
| 5534bf4df1 | |||
| 60522937af | |||
| 29be721f79 | |||
| 0c4ffad9ec | |||
| 03addbae55 | |||
| 0bab6be124 | |||
| b6def5300a | |||
| 1b35c9e27e | |||
| d1564525ad | |||
| 645f672a55 | |||
| a135199ab1 | |||
| 2a9971a69d | |||
| e2ada0efef | |||
| 69653a762d | |||
| c33fb95127 | |||
| ec6ca6bf73 | |||
| 078e88b223 | |||
| 1894cb703f | |||
| 27c283ab53 | |||
| 142955b109 | |||
| a61cd0f236 | |||
| cb1632e957 | |||
| dbf1f9ab8f | |||
| 137ab48aff | |||
| fc43def8a3 | |||
| 2a351016ed | |||
| dfa321a1dd | |||
| 895eb2ba6c | |||
| cd365de70c | |||
| 7f799f3948 | |||
| 234fbfd7e3 | |||
| b9909cef3d | |||
| d540e72fc7 | |||
| 13d0899776 | |||
| 4fefa7a01d | |||
| 90486607a1 | |||
| 0b303c766c | |||
| c371563bfc | |||
| d17d8eb3ee | |||
| bcaebdb2b7 | |||
| 43a9f59c18 | |||
| ff70409215 | |||
| 97a98a7031 | |||
| 533fb9cc44 | |||
| 59b99d2d60 | |||
| c796daed7c | |||
| 6e2c385fa5 | |||
| 9a0e4e0176 | |||
| 640f8e0e82 | |||
| 4eb580790d | |||
| a2c83d754b | |||
| 6f946b20ec | |||
| 4dda90502a | |||
| dc6dbba47c | |||
| 2ceabad360 | |||
| a00aee1495 | |||
| 4e31c9984d | |||
| b8772a1e40 | |||
| 42990d8264 | |||
| cf31418555 | |||
| 5db72b8ad9 | |||
| fe8f8bcf7b | |||
| d4d737de8d | |||
| 52f6e96ee8 | |||
| 44fa7b0f6b | |||
| bda561df4e | |||
| 8955420baf | |||
| 21ee256911 | |||
| 4aba6fae78 | |||
| fe06bc2f88 | |||
| 8dfb4cd02f | |||
| d1ade37827 | |||
| 9de49241fb | |||
| b24d50160a | |||
| e46463e69f | |||
| a3157c9572 | |||
| 0d4722680a | |||
| 7ab12597bb | |||
| b86a46c83c | |||
| 187a0a3ec0 | |||
| 111c18dec3 | |||
| 7a2b137912 | |||
| 791b9fbe81 | |||
| 0fdc0257aa | |||
| b6a77c4413 | |||
| 33438850a6 | |||
| fcbb3d3783 | |||
| acc8640c1e | |||
| c083cfd65e | |||
| 4cea81f93f | |||
| 2d36be753a | |||
| 738d29eaa9 | |||
| b536fb67a4 | |||
| b10c23a950 | |||
| 85a5cf7cb1 | |||
| 192f5cd647 | |||
| 7dceee64fe | |||
| 8ad6ae71c6 | |||
| 3ea85a28cf | |||
| 273ecdb786 | |||
| de40eb7306 | |||
| b9c44073ce | |||
| d6e5947ad2 | |||
| 668651ee01 | |||
| fb1cacc10e | |||
| 735e56c26f | |||
| 97de3dccbb | |||
| 690467cbe2 | |||
| 71efd8ffda | |||
| 9bb196ae6e | |||
| ce75418e40 | |||
| 78c7f09e28 | |||
| e7269ac84e | |||
| 34866e20a8 | |||
| 3ae2bee272 | |||
| d0fb958e99 | |||
| b941c63a53 | |||
| cf70c3fb05 | |||
| f249e72162 | |||
| 92e0b62c6b | |||
| cf32a5b204 | |||
| 7b0e06c825 | |||
| 3158bf9093 | |||
| 01fade764c | |||
| 210c2419be | |||
| da05163d51 | |||
| f3e2bb5104 | |||
| 7a4c1086b5 | |||
| e89feb9635 | |||
| 5f72766c27 | |||
| 85ae57040d | |||
| d55a4a279f | |||
| bee9299693 | |||
| 9529fcec96 | |||
| bcec168e23 | |||
| 102a332616 | |||
| a280942f02 | |||
| 637dba5c2a | |||
| 24f292d081 | |||
| fa5c99e48a | |||
| 48f1a2c9b2 | |||
| 50ebbd63c6 | |||
| 4e5f63ff45 | |||
| de709e72a8 | |||
| 56d3c8f071 | |||
| ce89adecc1 | |||
| bc7a85063d | |||
| 0574f1e020 | |||
| f9fdd60e2e | |||
| 1c1eecabc0 | |||
| abd3fd004e | |||
| 15ee353488 | |||
| e75efbfd31 | |||
| 1c97a7ecb3 | |||
| fccd3e9fba | |||
| 4cb13b33e0 | |||
| 629802f2ab | |||
| afb1754528 | |||
| dbd67c6c89 | |||
| ed01bdb9dd | |||
| b54821d8ab | |||
| 89c6a79b6e | |||
| cd0412bddc | |||
| e42262f0f5 | |||
| 0a3eeab273 | |||
| e4e110e28f | |||
| 0726623389 | |||
| fd9d334d01 | |||
| 840eb14121 | |||
| 8fef196ee4 | |||
| 9c756f1ec0 | |||
| 4c29eea790 | |||
| 6dd2b4607f | |||
| 1e9ae88f53 | |||
| 5cc3902ab9 | |||
| c8e09e2d6d | |||
| e2a2ba116c | |||
| 0a9d24a218 | |||
| c222183669 | |||
| 140f9beee7 | |||
| 28ce892617 | |||
| 1e6d3ff99b | |||
| fba1b92cbf | |||
| ce1686379d | |||
| 79a20e9e33 | |||
| e9cd73f78e | |||
| 0be7f36d51 | |||
| 4c6cb6e359 | |||
| 82bde8d166 | |||
| 465392b618 | |||
| f3c6b9f05a | |||
| 2f1945eaf2 | |||
| b4d8a55b2a | |||
| 0e6ce8fa50 | |||
| a295c38ba3 | |||
| 295730ba1e | |||
| ac0d8f61c5 | |||
| b811588fa0 | |||
| 5fcdf0ff2b | |||
| 650b723da3 | |||
| 97920be33a | |||
| 58bbaa9e80 | |||
| 94f152730c | |||
| 535e3d4372 | |||
| 2ea43c8986 | |||
| 71fe2a5534 | |||
| f3ffcfd61e | |||
| bf27b28554 | |||
| 344602d27e | |||
| 64c483cf80 | |||
| 19091aacc7 | |||
| ef9028d798 | |||
| 1668cd19d3 | |||
| 134f268cee | |||
| c473633676 | |||
| 6a3a82007c | |||
| 1d6ef76cfb | |||
| c8e3959435 | |||
| 796f412a1e | |||
| fa854a2108 | |||
| 3a097ff2d2 | |||
| 8463bfc1e5 | |||
| 7a72b4c624 | |||
| 670c179417 | |||
| 1b1d868837 | |||
| d9704d02bb | |||
| 1349548367 | |||
| 18b1604fc8 | |||
| 0def7da5a8 | |||
| 4bb45c8252 | |||
| bb99b31eb0 | |||
| 84397183f3 | |||
| aeae265777 | |||
| a9c5df5da1 | |||
| 96576c4de9 | |||
| 9ec68e5829 | |||
| face857d5e | |||
| 85a1cc9b4f | |||
| 630501b93d | |||
| 8bbc2995ca | |||
| 7d3872df57 | |||
| 1ed228b92b | |||
| b605cd1bb9 | |||
| fea4e8e5b6 | |||
| 1df8b5785b | |||
| 981a75d7c9 | |||
| 11cc7014b3 | |||
| 0b667c88fa | |||
| 054ab1adaf | |||
| f1f8386f2e | |||
| ba8c3970b0 | |||
| 2f36b26a5c | |||
| 9b4edb3a1d | |||
| b8adc5ffa2 | |||
| bd90cafda7 | |||
| 6d43a08a1d | |||
| e71b8598ae | |||
| 95d0f437e3 | |||
| c95ee3968a | |||
| c22dd4ada5 | |||
| 727a40fc5a | |||
| ce84a5f1d3 | |||
| e6fda1c410 | |||
| 294dccc5be | |||
| da346a8878 | |||
| c5ccb995ad | |||
| 05ab569a80 | |||
| ab3f4971f0 | |||
| 47e238aa13 | |||
| e49b6c708b | |||
| eb7250792b | |||
| 7e5066b878 | |||
| 889e17816f | |||
| b1b9702daf | |||
| 32728d2f1d | |||
| 807a097387 | |||
| 794ee15386 | |||
| 2359417804 | |||
| 7950f3cdc5 | |||
| b87f8f35ee | |||
| 9e53405f43 | |||
| c6c1d8fa86 | |||
| 8aa5c2b45d | |||
| 414fd694c0 | |||
| 7e82809592 | |||
| 0dae5db30e | |||
| 5c24f0f0f3 | |||
| c2591e9b39 | |||
| 8ce0dee6da | |||
| 16daba8ea9 | |||
| 8b4074ee77 | |||
| 85fbd8793a | |||
| 65705e2091 | |||
| 385a385c62 | |||
| e1edb0282a | |||
| 5484f69164 | |||
| cf1e0825c1 | |||
| 86faa44915 | |||
| a0b23cbf02 | |||
| e8ffb22c0d | |||
| 4d04ae0111 | |||
| 14a3da9b16 | |||
| 034db9f20f | |||
| 8f3f073017 | |||
| 58b3af4c29 | |||
| 4821d09a48 | |||
| b3d9d51b51 | |||
| 6b33abb179 | |||
| a043b2a763 | |||
| 0c3d4a8a37 | |||
| 9afc5fef11 | |||
| a8a54c0568 | |||
| 451ee2d78e | |||
| 820107d15e | |||
| a51f831ae4 | |||
| 1b45e5766a | |||
| 59c8951341 | |||
| aca61b5dda | |||
| 908affd24f | |||
| f878d2ebd5 | |||
| 778e516270 | |||
| 6d58492ad0 | |||
| fecfabb168 | |||
| 80765eb453 | |||
| f1073dca04 | |||
| da65fe5a52 | |||
| 3f0f739e17 | |||
| 5023e2ad52 | |||
| 810cde1c84 | |||
| 9436efb80e | |||
| 48230890c5 | |||
| f1e8dcf38e | |||
| 2cf10a6003 | |||
| 23a53d8008 | |||
| 9956589ed5 | |||
| 81a3f66d78 | |||
| a8247bc619 | |||
| 66a9ccb10e | |||
| 53fe1b328e | |||
| 2753ec757b | |||
| dcd2232f69 | |||
| 0156f1355a | |||
| 61bf901048 | |||
| 7870b58356 | |||
| 8cc7e6aa90 | |||
| 7b50388fef | |||
| e704990322 | |||
| 2a4b8ce42d | |||
| 108cca687c | |||
| bca8c115c7 | |||
| b49bd52a53 | |||
| 27bd640812 | |||
| 8d5cda8464 | |||
| 389b9b5fe7 | |||
| 27478b6f71 | |||
| 480f858fc3 | |||
| 7d752c5a60 | |||
| 33b7841300 | |||
| 2244b92eb0 | |||
| d0464fbff7 | |||
| 98eddf9b29 | |||
| d23a40c1bb | |||
| 55cecace29 | |||
| 3da0deaa50 | |||
| 585550a5be | |||
| 5b7b8abf9f | |||
| 2aab0ce2f6 | |||
| a157c56d7d | |||
| 6c45593ee4 | |||
| 1175d54fb7 | |||
| cfdbbee845 | |||
| c1583bf2b8 | |||
| 7385b50249 | |||
| db6aaf5110 | |||
| c4a4501d71 | |||
| a3ae14d090 | |||
| dc4bb0bf08 | |||
| c69a3e083f | |||
| c790bd2a69 | |||
| 60cbbacdb3 | |||
| befc7edc17 | |||
| 3897ccb3f9 | |||
| 11c5fd78ad | |||
| cbfdba3826 | |||
| 5985b7edaf | |||
| d28a0e66c8 | |||
| 0ca4db1616 | |||
| 72b3438dfc | |||
| c7051ac748 | |||
| a065db9838 | |||
| 24c4df7831 | |||
| a077ae039e | |||
| 20b34d3b43 | |||
| b5451d1905 | |||
| e26960f7f8 | |||
| 228b5a4a63 | |||
| 28db9d4989 | |||
| 5fff0d936d | |||
| 8eb195edf0 | |||
| 8b2e6baf78 | |||
| 3ca0597a7e | |||
| 4e54aaf796 | |||
| 4cddcbe194 | |||
| 54b6798ef6 | |||
| 229a9d90ba | |||
| 3bcd568c86 | |||
| dc56077aac | |||
| 46bd36e17c | |||
| 5dee9118c7 | |||
| a916aa9420 | |||
| d9c63d0784 | |||
| 41dcb969e8 | |||
| 6dbaea34ba | |||
| ce17301b8b | |||
| b0e78c6be4 | |||
| 898f65fa46 | |||
| 84e384196d | |||
| d827b101d9 | |||
| c45ab6b304 | |||
| cc9d85b293 | |||
| 02493d83be | |||
| a1280c672a | |||
| a740f76772 | |||
| a887db398b | |||
| e1ae3c71f3 | |||
| d094209774 | |||
| 485a64aaf9 | |||
| 3e57cd5917 | |||
| b6c4cfec37 | |||
| 94853752a1 | |||
| bd366f675e | |||
| 22b1af7eb3 | |||
| fd6178cad6 | |||
| 338fb67853 | |||
| 0a71fe329c | |||
| a4acc83282 | |||
| 57de28744c | |||
| 6d31ec521b | |||
| 7ad3d17e59 | |||
| 05e931b9a5 | |||
| 2db2b53bbf | |||
| d5ec3efe49 | |||
| 71fc318474 | |||
| 5ee2fc0562 | |||
| ca53daf697 | |||
| c3b9ee314b | |||
| 993710eb16 | |||
| dbaf2893e3 | |||
| 34a7108b73 | |||
| db2bafd3f3 | |||
| 1b6fbf1023 | |||
| c81bab18ad | |||
| a39199e9f7 | |||
| b0ad1e56e8 | |||
| ab53448bc3 | |||
| c50c9d8862 | |||
| cc4f289758 | |||
| a2a9041549 | |||
| a65950acca | |||
| 0fbf4d0c5d | |||
| 983bf8c090 | |||
| f2afa89ff1 | |||
| 8b4f9c47c4 | |||
| 06d8a44f18 | |||
| fffdceca95 | |||
| 794b769e6b | |||
| 927ec7d38e | |||
| cd0b2d312c | |||
| ea118e11a0 | |||
| 0ff4882cab | |||
| 7407d71417 | |||
| 9faa11fd9a | |||
| 5310bd87ae | |||
| 99091d5925 | |||
| 320a059e4b | |||
| 8a596951bf | |||
| 350406e827 | |||
| 7ec3cac7d6 | |||
| ad47bd132b | |||
| 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 | |||
| 38d4f0e06c | |||
| 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 |
@@ -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: Anything else!
|
||||
about: Whatever is on your mind
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule: [cron: "40 1 * * *"]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test suite
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd test_suite && cargo test --features unstable
|
||||
|
||||
windows:
|
||||
name: Test suite (windows)
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
|
||||
|
||||
stable:
|
||||
name: Rust stable
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde_test && cargo build
|
||||
- run: cd serde_test && cargo test --features serde/derive,serde/rc
|
||||
|
||||
beta:
|
||||
name: Rust beta
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@beta
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd test_suite && cargo test
|
||||
|
||||
nightly:
|
||||
name: Rust nightly ${{matrix.os == 'windows' && '(windows)' || ''}}
|
||||
runs-on: ${{matrix.os}}-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu, windows]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cd serde && cargo build
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde && cargo build --no-default-features --features alloc
|
||||
- run: cd serde && cargo build --no-default-features --features rc,alloc
|
||||
- run: cd serde && cargo test --features derive,rc,unstable
|
||||
- run: cd test_suite/no_std && cargo build
|
||||
if: matrix.os != 'windows'
|
||||
|
||||
msrv:
|
||||
name: Rust 1.13.0
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@1.13.0
|
||||
- name: Get timestamp for cache
|
||||
id: date
|
||||
run: echo ::set-output name=yearmo::$(date +%Y%m)
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.cargo/registry/index
|
||||
key: cargo-registry-index-${{steps.date.outputs.yearmo}}
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde_test && cargo build
|
||||
|
||||
build:
|
||||
name: Rust ${{matrix.rust}}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [1.19.0, 1.20.0, 1.21.0, 1.25.0, 1.26.0, 1.34.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde && cargo build
|
||||
|
||||
more:
|
||||
name: Rust ${{matrix.rust}}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [1.27.0, 1.28.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
# Work around failing to parse manifest because editions are unstable.
|
||||
- run: sed -i /test_suite/d Cargo.toml
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde && cargo build
|
||||
|
||||
derive:
|
||||
name: Rust 1.31.0
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@1.31.0
|
||||
- run: cd serde_derive && cargo check
|
||||
|
||||
alloc:
|
||||
name: Rust 1.36.0
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@1.36.0
|
||||
- run: cd serde && cargo build --no-default-features --features alloc
|
||||
|
||||
emscripten:
|
||||
name: Emscripten
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 9
|
||||
- name: Install cargo-web
|
||||
run: |
|
||||
CARGO_WEB_RELEASE=$(curl -L -s -H Accept:application/json https://github.com/koute/cargo-web/releases/latest)
|
||||
CARGO_WEB_VERSION=$(echo "${CARGO_WEB_RELEASE}" | jq -r .tag_name)
|
||||
CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/${CARGO_WEB_VERSION}/cargo-web-x86_64-unknown-linux-gnu.gz"
|
||||
mkdir -p ~/.cargo/bin
|
||||
curl -L "${CARGO_WEB_URL}" | gzip -d > ~/.cargo/bin/cargo-web
|
||||
chmod +x ~/.cargo/bin/cargo-web
|
||||
- run: cd test_suite && cargo web test --target=asmjs-unknown-emscripten --nodejs
|
||||
continue-on-error: true
|
||||
- run: cd test_suite && cargo web test --target=wasm32-unknown-emscripten --nodejs
|
||||
continue-on-error: true
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@clippy
|
||||
# The need for -Aredundant_field_names here is a Clippy bug.
|
||||
# https://github.com/rust-lang/rust-clippy/issues/5356
|
||||
- run: cd serde && cargo clippy --features rc,unstable -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd serde_derive && cargo clippy -- -D clippy::all
|
||||
- run: cd serde_test && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd test_suite && cargo clippy --tests --features unstable -- -D clippy::all -A clippy::redundant_field_names
|
||||
- run: cd test_suite/no_std && cargo clippy -- -D clippy::all -A clippy::redundant_field_names
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
sudo: false
|
||||
language: rust
|
||||
cache: cargo
|
||||
|
||||
# run builds for all the trains (and more)
|
||||
rust:
|
||||
- 1.13.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- rust: nightly
|
||||
env: CLIPPY=true
|
||||
|
||||
script: ./travis.sh
|
||||
+1
-6
@@ -4,11 +4,6 @@ Serde welcomes contribution from everyone in the form of suggestions, bug
|
||||
reports, pull requests, and feedback. This document gives some guidance if you
|
||||
are thinking of helping us.
|
||||
|
||||
Please reach out here in a GitHub issue or in the #serde IRC channel on
|
||||
[`irc.mozilla.org`] if we can do anything to help you contribute.
|
||||
|
||||
[`irc.mozilla.org`]: https://wiki.mozilla.org/IRC
|
||||
|
||||
## Submitting bug reports and feature requests
|
||||
|
||||
Serde development is spread across lots of repositories, but this serde-rs/serde
|
||||
@@ -63,4 +58,4 @@ In all Serde-related forums, we follow the [Rust Code of Conduct]. For
|
||||
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
||||
instead of the Rust moderation team.
|
||||
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/conduct.html
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
Copyright (c) 2014 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc]
|
||||
# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.13+]][Rust 1.13] [![serde_derive: rustc 1.31+]][Rust 1.31]
|
||||
|
||||
[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master
|
||||
[travis]: https://travis-ci.org/serde-rs/serde
|
||||
[Build Status]: https://img.shields.io/github/workflow/status/serde-rs/serde/CI/master
|
||||
[actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster
|
||||
[Latest Version]: https://img.shields.io/crates/v/serde.svg
|
||||
[crates.io]: https://crates.io/crates/serde
|
||||
[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: rustc 1.13+]: https://img.shields.io/badge/serde-rustc_1.13+-lightgray.svg
|
||||
[serde_derive: rustc 1.31+]: https://img.shields.io/badge/serde_derive-rustc_1.31+-lightgray.svg
|
||||
[Rust 1.13]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html
|
||||
[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html
|
||||
|
||||
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
|
||||
|
||||
@@ -15,7 +17,7 @@ You may be looking for:
|
||||
|
||||
- [An overview of Serde](https://serde.rs/)
|
||||
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html)
|
||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||
- [Examples](https://serde.rs/examples.html)
|
||||
- [API documentation](https://docs.serde.rs/serde/)
|
||||
- [Release notes](https://github.com/serde-rs/serde/releases)
|
||||
@@ -25,19 +27,17 @@ You may be looking for:
|
||||
<details>
|
||||
<summary>
|
||||
Click to show Cargo.toml.
|
||||
<a href="http://play.integer32.com/?gist=9003c5b88c1f4989941925d7190c6eec" target="_blank">Run this code in the playground.</a>
|
||||
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||
</summary>
|
||||
|
||||
```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"
|
||||
# required when using Serde. The "derive" feature is only required when
|
||||
# using #[derive(Serialize, Deserialize)] to make Serde work with structs
|
||||
# and enums defined in your crate.
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
# Each data format lives in its own crate; the sample code below uses JSON
|
||||
# but you may be using a different one.
|
||||
@@ -48,11 +48,7 @@ serde_json = "1.0"
|
||||
<p></p>
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Point {
|
||||
@@ -79,26 +75,37 @@ fn main() {
|
||||
|
||||
## Getting help
|
||||
|
||||
Serde developers live in the #serde channel on
|
||||
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC). The #rust channel is also a
|
||||
good resource with generally faster response time but less specific knowledge
|
||||
about Serde. If IRC is not your thing or you don't get a good response, we are
|
||||
happy to respond to [GitHub issues](https://github.com/serde-rs/serde/issues/new)
|
||||
as well.
|
||||
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
||||
congregate will be able to help you out. For chat, consider trying the
|
||||
[#general] or [#beginners] channels of the unofficial community Discord, the
|
||||
[#rust-usage] channel of the official Rust Project Discord, or the
|
||||
[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag
|
||||
on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned
|
||||
weekly easy questions post, or the Rust [Discourse forum][discourse]. It's
|
||||
acceptable to file a support issue in this repo but they tend not to get as many
|
||||
eyes as any of the above and may get closed without a response after some time.
|
||||
|
||||
## License
|
||||
[#general]: https://discord.com/channels/273534239310479360/274215136414400513
|
||||
[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281
|
||||
[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848
|
||||
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: https://www.reddit.com/r/rust
|
||||
[discourse]: https://users.rust-lang.org
|
||||
|
||||
Serde is licensed under either of
|
||||
<br>
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
||||
http://opensource.org/licenses/MIT)
|
||||
#### License
|
||||
|
||||
at your option.
|
||||
<sup>
|
||||
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
|
||||
</sup>
|
||||
|
||||
### Contribution
|
||||
<br>
|
||||
|
||||
<sub>
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
</sub>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_RUST_CHANNEL: stable
|
||||
- APPVEYOR_RUST_CHANNEL: nightly
|
||||
|
||||
install:
|
||||
# Install rust, x86_64-pc-windows-msvc host
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain %APPVEYOR_RUST_CHANNEL%
|
||||
- set PATH=C:\msys64\usr\bin;%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- sh -c 'PATH=`rustc --print sysroot`/bin:$PATH ./travis.sh'
|
||||
@@ -0,0 +1,62 @@
|
||||
<!-- Serde readme rendered on crates.io -->
|
||||
|
||||
**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.**
|
||||
|
||||
---
|
||||
|
||||
You may be looking for:
|
||||
|
||||
- [An overview of Serde](https://serde.rs/)
|
||||
- [Data formats supported by Serde](https://serde.rs/#data-formats)
|
||||
- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html)
|
||||
- [Examples](https://serde.rs/examples.html)
|
||||
- [API documentation](https://docs.serde.rs/serde/)
|
||||
- [Release notes](https://github.com/serde-rs/serde/releases)
|
||||
|
||||
## Serde in action
|
||||
|
||||
```rust
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let point = Point { x: 1, y: 2 };
|
||||
|
||||
// Convert the Point to a JSON string.
|
||||
let serialized = serde_json::to_string(&point).unwrap();
|
||||
|
||||
// Prints serialized = {"x":1,"y":2}
|
||||
println!("serialized = {}", serialized);
|
||||
|
||||
// Convert the JSON string back to a Point.
|
||||
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
// Prints deserialized = Point { x: 1, y: 2 }
|
||||
println!("deserialized = {:?}", deserialized);
|
||||
}
|
||||
```
|
||||
|
||||
## Getting help
|
||||
|
||||
Serde is one of the most widely used Rust libraries so any place that Rustaceans
|
||||
congregate will be able to help you out. For chat, consider trying the
|
||||
[#general] or [#beginners] channels of the unofficial community Discord, the
|
||||
[#rust-usage] channel of the official Rust Project Discord, or the
|
||||
[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag
|
||||
on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned
|
||||
weekly easy questions post, or the Rust [Discourse forum][discourse]. It's
|
||||
acceptable to file a support issue in this repo but they tend not to get as many
|
||||
eyes as any of the above and may get closed without a response after some time.
|
||||
|
||||
[#general]: https://discord.com/channels/273534239310479360/274215136414400513
|
||||
[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281
|
||||
[#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848
|
||||
[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: https://www.reddit.com/r/rust
|
||||
[discourse]: https://users.rust-lang.org
|
||||
@@ -1 +0,0 @@
|
||||
error_on_line_overflow = false
|
||||
+14
-27
@@ -1,41 +1,37 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.38" # remember to update html_root_url
|
||||
version = "1.0.116" # remember to update html_root_url and serde_derive dependency
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "A generic serialization/deserialization framework"
|
||||
homepage = "https://serde.rs"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://docs.serde.rs/serde/"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
categories = ["encoding"]
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
appveyor = { repository = "serde-rs/serde" }
|
||||
readme = "crates-io.md"
|
||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
serde_derive = { version = "1.0", optional = true, path = "../serde_derive" }
|
||||
serde_derive = { version = "=1.0.116", optional = true, path = "../serde_derive" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["derive", "rc"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
|
||||
### 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.
|
||||
# Provide derive(Serialize, Deserialize) macros.
|
||||
derive = ["serde_derive"]
|
||||
|
||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||
@@ -51,18 +47,9 @@ 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"]
|
||||
alloc = []
|
||||
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
rc = []
|
||||
|
||||
# Get serde_derive picked up by the Integer 32 playground. Not public API.
|
||||
#
|
||||
# http://play.integer32.com/
|
||||
playground = ["serde_derive"]
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str::{self, FromStr};
|
||||
|
||||
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||
// opening a GitHub issue if your build environment requires some way to enable
|
||||
// these cfgs other than by executing our build script.
|
||||
fn main() {
|
||||
let minor = match rustc_minor_version() {
|
||||
Some(minor) => minor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";
|
||||
|
||||
// std::collections::Bound was stabilized in Rust 1.17
|
||||
// but it was moved to core::ops later in Rust 1.26:
|
||||
// https://doc.rust-lang.org/core/ops/enum.Bound.html
|
||||
if minor >= 26 {
|
||||
println!("cargo:rustc-cfg=ops_bound");
|
||||
} else if minor >= 17 && cfg!(feature = "std") {
|
||||
println!("cargo:rustc-cfg=collections_bound");
|
||||
}
|
||||
|
||||
// core::cmp::Reverse stabilized in Rust 1.19:
|
||||
// https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html
|
||||
if minor >= 19 {
|
||||
println!("cargo:rustc-cfg=core_reverse");
|
||||
}
|
||||
|
||||
// CString::into_boxed_c_str and PathBuf::into_boxed_path stabilized in Rust 1.20:
|
||||
// https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
|
||||
// https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.into_boxed_path
|
||||
if minor >= 20 {
|
||||
println!("cargo:rustc-cfg=de_boxed_c_str");
|
||||
println!("cargo:rustc-cfg=de_boxed_path");
|
||||
}
|
||||
|
||||
// From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21:
|
||||
// https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>>
|
||||
// https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>>
|
||||
if minor >= 21 {
|
||||
println!("cargo:rustc-cfg=de_rc_dst");
|
||||
}
|
||||
|
||||
// Duration available in core since Rust 1.25:
|
||||
// https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations
|
||||
if minor >= 25 {
|
||||
println!("cargo:rustc-cfg=core_duration");
|
||||
}
|
||||
|
||||
// 128-bit integers stabilized in Rust 1.26:
|
||||
// https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
|
||||
//
|
||||
// Disabled on Emscripten targets as Emscripten doesn't
|
||||
// currently support integers larger than 64 bits.
|
||||
if minor >= 26 && !emscripten {
|
||||
println!("cargo:rustc-cfg=integer128");
|
||||
}
|
||||
|
||||
// Inclusive ranges methods stabilized in Rust 1.27:
|
||||
// https://github.com/rust-lang/rust/pull/50758
|
||||
if minor >= 27 {
|
||||
println!("cargo:rustc-cfg=range_inclusive");
|
||||
}
|
||||
|
||||
// Non-zero integers stabilized in Rust 1.28:
|
||||
// https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations
|
||||
if minor >= 28 {
|
||||
println!("cargo:rustc-cfg=num_nonzero");
|
||||
}
|
||||
|
||||
// TryFrom, Atomic types, and non-zero signed integers stabilized in Rust 1.34:
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
|
||||
if minor >= 34 {
|
||||
println!("cargo:rustc-cfg=core_try_from");
|
||||
println!("cargo:rustc-cfg=num_nonzero_signed");
|
||||
|
||||
// Whitelist of archs that support std::sync::atomic module. Ideally we
|
||||
// would use #[cfg(target_has_atomic = "...")] but it is not stable yet.
|
||||
// Instead this is based on rustc's src/librustc_target/spec/*.rs.
|
||||
let has_atomic64 = target.starts_with("x86_64")
|
||||
|| target.starts_with("i686")
|
||||
|| target.starts_with("aarch64")
|
||||
|| target.starts_with("powerpc64")
|
||||
|| target.starts_with("sparc64")
|
||||
|| target.starts_with("mips64el");
|
||||
let has_atomic32 = has_atomic64 || emscripten;
|
||||
if has_atomic64 {
|
||||
println!("cargo:rustc-cfg=std_atomic64");
|
||||
}
|
||||
if has_atomic32 {
|
||||
println!("cargo:rustc-cfg=std_atomic");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = match env::var_os("RUSTC") {
|
||||
Some(rustc) => rustc,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let output = match Command::new(rustc).arg("--version").output() {
|
||||
Ok(output) => output,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let version = match str::from_utf8(&output.stdout) {
|
||||
Ok(version) => version,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let next = match pieces.next() {
|
||||
Some(next) => next,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
u32::from_str(next).ok()
|
||||
}
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../crates-io.md
|
||||
@@ -1,11 +1,3 @@
|
||||
// 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::*;
|
||||
|
||||
macro_rules! int_to_int {
|
||||
@@ -39,12 +31,10 @@ macro_rules! uint_to {
|
||||
}
|
||||
|
||||
pub trait FromPrimitive: Sized {
|
||||
fn from_isize(n: isize) -> Option<Self>;
|
||||
fn from_i8(n: i8) -> Option<Self>;
|
||||
fn from_i16(n: i16) -> Option<Self>;
|
||||
fn from_i32(n: i32) -> Option<Self>;
|
||||
fn from_i64(n: i64) -> Option<Self>;
|
||||
fn from_usize(n: usize) -> Option<Self>;
|
||||
fn from_u8(n: u8) -> Option<Self>;
|
||||
fn from_u16(n: u16) -> Option<Self>;
|
||||
fn from_u32(n: u32) -> Option<Self>;
|
||||
@@ -54,10 +44,6 @@ pub trait FromPrimitive: Sized {
|
||||
macro_rules! impl_from_primitive_for_int {
|
||||
($t:ident) => {
|
||||
impl FromPrimitive for $t {
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
int_to_int!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
int_to_int!($t, n)
|
||||
@@ -75,10 +61,6 @@ macro_rules! impl_from_primitive_for_int {
|
||||
int_to_int!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
uint_to!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
uint_to!($t, n)
|
||||
}
|
||||
@@ -101,10 +83,6 @@ macro_rules! impl_from_primitive_for_int {
|
||||
macro_rules! impl_from_primitive_for_uint {
|
||||
($t:ident) => {
|
||||
impl FromPrimitive for $t {
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
int_to_uint!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
int_to_uint!($t, n)
|
||||
@@ -122,10 +100,6 @@ macro_rules! impl_from_primitive_for_uint {
|
||||
int_to_uint!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
uint_to!($t, n)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
uint_to!($t, n)
|
||||
}
|
||||
@@ -148,10 +122,6 @@ macro_rules! impl_from_primitive_for_uint {
|
||||
macro_rules! impl_from_primitive_for_float {
|
||||
($t:ident) => {
|
||||
impl FromPrimitive for $t {
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
Some(n as Self)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
Some(n as Self)
|
||||
@@ -169,10 +139,6 @@ macro_rules! impl_from_primitive_for_float {
|
||||
Some(n as Self)
|
||||
}
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
Some(n as Self)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
Some(n as Self)
|
||||
}
|
||||
@@ -204,3 +170,91 @@ impl_from_primitive_for_uint!(u32);
|
||||
impl_from_primitive_for_uint!(u64);
|
||||
impl_from_primitive_for_float!(f32);
|
||||
impl_from_primitive_for_float!(f64);
|
||||
|
||||
serde_if_integer128! {
|
||||
impl FromPrimitive for i128 {
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_i64(n: i64) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u64(n: u64) -> Option<Self> {
|
||||
Some(n as i128)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromPrimitive for u128 {
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
if n >= 0 {
|
||||
Some(n as u128)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
if n >= 0 {
|
||||
Some(n as u128)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
if n >= 0 {
|
||||
Some(n as u128)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn from_i64(n: i64) -> Option<Self> {
|
||||
if n >= 0 {
|
||||
Some(n as u128)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
Some(n as u128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
Some(n as u128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
Some(n as u128)
|
||||
}
|
||||
#[inline]
|
||||
fn from_u64(n: u64) -> Option<Self> {
|
||||
Some(n as u128)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-18
@@ -1,14 +1,8 @@
|
||||
// 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};
|
||||
use de::{
|
||||
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
|
||||
};
|
||||
|
||||
/// An efficient way of discarding data from a deserializer.
|
||||
///
|
||||
@@ -16,18 +10,20 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
||||
/// any type, except that it does not store any information about the data that
|
||||
/// gets deserialized.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// use std::fmt;
|
||||
/// use std::marker::PhantomData;
|
||||
///
|
||||
/// use serde::de::{self, Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess, IgnoredAny};
|
||||
/// use serde::de::{
|
||||
/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor,
|
||||
/// };
|
||||
///
|
||||
/// /// 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> {
|
||||
@@ -45,16 +41,22 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> Visitor<'de> for NthElement<T>
|
||||
/// where T: Deserialize<'de>
|
||||
/// 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)
|
||||
/// 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>
|
||||
/// where
|
||||
/// A: SeqAccess<'de>,
|
||||
/// {
|
||||
/// // Skip over the first `n` elements.
|
||||
/// for i in 0..self.n {
|
||||
@@ -82,19 +84,22 @@ use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> DeserializeSeed<'de> for NthElement<T>
|
||||
/// where T: Deserialize<'de>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = T;
|
||||
///
|
||||
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// deserializer.deserialize_seq(self)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
/// # where D: Deserializer<'de>
|
||||
/// # 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
|
||||
@@ -202,6 +207,13 @@ impl<'de> Visitor<'de> for IgnoredAny {
|
||||
let _ = bytes;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: EnumAccess<'de>,
|
||||
{
|
||||
data.variant::<IgnoredAny>()?.1.newtype_variant()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for IgnoredAny {
|
||||
|
||||
+755
-276
File diff suppressed because it is too large
Load Diff
+358
-127
@@ -1,11 +1,3 @@
|
||||
// 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.
|
||||
|
||||
//! Generic data structure deserialization framework.
|
||||
//!
|
||||
//! The two most important traits in this module are [`Deserialize`] and
|
||||
@@ -24,8 +16,7 @@
|
||||
//!
|
||||
//! Additionally, Serde provides a procedural macro called [`serde_derive`] to
|
||||
//! automatically generate [`Deserialize`] implementations for structs and enums
|
||||
//! in your program. See the [codegen section of the manual] for how to use
|
||||
//! this.
|
||||
//! in your program. See the [derive section of the manual] for how to use this.
|
||||
//!
|
||||
//! In rare cases it may be necessary to implement [`Deserialize`] manually for
|
||||
//! some type in your program. See the [Implementing `Deserialize`] section of
|
||||
@@ -52,12 +43,12 @@
|
||||
//!
|
||||
//! - **Primitive types**:
|
||||
//! - bool
|
||||
//! - i8, i16, i32, i64, isize
|
||||
//! - u8, u16, u32, u64, usize
|
||||
//! - i8, i16, i32, i64, i128, isize
|
||||
//! - u8, u16, u32, u64, u128, usize
|
||||
//! - f32, f64
|
||||
//! - char
|
||||
//! - **Compound types**:
|
||||
//! - [T; 0] through [T; 32]
|
||||
//! - \[T; 0\] through \[T; 32\]
|
||||
//! - tuples up to size 16
|
||||
//! - **Common standard library types**:
|
||||
//! - String
|
||||
@@ -66,15 +57,15 @@
|
||||
//! - PhantomData\<T\>
|
||||
//! - **Wrapper types**:
|
||||
//! - Box\<T\>
|
||||
//! - Box\<[T]\>
|
||||
//! - Box\<\[T\]\>
|
||||
//! - Box\<str\>
|
||||
//! - Rc\<T\>
|
||||
//! - Arc\<T\>
|
||||
//! - Cow\<'a, T\>
|
||||
//! - Cell\<T\>
|
||||
//! - RefCell\<T\>
|
||||
//! - Mutex\<T\>
|
||||
//! - RwLock\<T\>
|
||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - **Collection types**:
|
||||
//! - BTreeMap\<K, V\>
|
||||
//! - BTreeSet\<T\>
|
||||
@@ -84,10 +75,9 @@
|
||||
//! - LinkedList\<T\>
|
||||
//! - VecDeque\<T\>
|
||||
//! - Vec\<T\>
|
||||
//! - EnumSet\<T\> (unstable)
|
||||
//! - **Zero-copy types**:
|
||||
//! - &str
|
||||
//! - &[u8]
|
||||
//! - &\[u8\]
|
||||
//! - **FFI types**:
|
||||
//! - CString
|
||||
//! - Box\<CStr\>
|
||||
@@ -98,8 +88,10 @@
|
||||
//! - Path
|
||||
//! - PathBuf
|
||||
//! - Range\<T\>
|
||||
//! - NonZero\<T\> (unstable, deprecated)
|
||||
//! - num::NonZero* (unstable)
|
||||
//! - RangeInclusive\<T\>
|
||||
//! - Bound\<T\>
|
||||
//! - num::NonZero*
|
||||
//! - `!` *(unstable)*
|
||||
//! - **Net types**:
|
||||
//! - IpAddr
|
||||
//! - Ipv4Addr
|
||||
@@ -112,12 +104,12 @@
|
||||
//! [`Deserialize`]: ../trait.Deserialize.html
|
||||
//! [`Deserializer`]: ../trait.Deserializer.html
|
||||
//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html
|
||||
//! [`bincode`]: https://github.com/TyOverby/bincode
|
||||
//! [`bincode`]: https://github.com/servo/bincode
|
||||
//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map
|
||||
//! [`serde_derive`]: https://crates.io/crates/serde_derive
|
||||
//! [`serde_json`]: https://github.com/serde-rs/json
|
||||
//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml
|
||||
//! [codegen section of the manual]: https://serde.rs/codegen.html
|
||||
//! [derive section of the manual]: https://serde.rs/derive.html
|
||||
//! [data formats]: https://serde.rs/#data-formats
|
||||
|
||||
use lib::*;
|
||||
@@ -133,6 +125,13 @@ mod utf8;
|
||||
|
||||
pub use self::ignored_any::IgnoredAny;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(no_inline)]
|
||||
pub use std::error::Error as StdError;
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[doc(no_inline)]
|
||||
pub use std_error::Error as StdError;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! declare_error_trait {
|
||||
@@ -150,12 +149,19 @@ macro_rules! declare_error_trait {
|
||||
///
|
||||
/// Most deserializers should only need to provide the `Error::custom` method
|
||||
/// and inherit the default behavior for the other methods.
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website shows an error
|
||||
/// type appropriate for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait Error: Sized $(+ $($supertrait)::+)* {
|
||||
/// Raised when there is general error when deserializing a type.
|
||||
///
|
||||
/// The message should not be capitalized and should not end with a period.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use std::str::FromStr;
|
||||
/// #
|
||||
/// # struct IpAddr;
|
||||
@@ -172,9 +178,10 @@ macro_rules! declare_error_trait {
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for IpAddr {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// let s = try!(String::deserialize(deserializer));
|
||||
/// let s = String::deserialize(deserializer)?;
|
||||
/// s.parse().map_err(de::Error::custom)
|
||||
/// }
|
||||
/// }
|
||||
@@ -196,6 +203,7 @@ macro_rules! declare_error_trait {
|
||||
/// For example if we try to deserialize a String out of a JSON file
|
||||
/// containing an integer, the unexpected type is the integer and the
|
||||
/// expected type is the string.
|
||||
#[cold]
|
||||
fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self {
|
||||
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
|
||||
}
|
||||
@@ -213,6 +221,7 @@ macro_rules! declare_error_trait {
|
||||
/// For example if we try to deserialize a String out of some binary data
|
||||
/// that is not valid UTF-8, the unexpected value is the bytes and the
|
||||
/// expected value is a string.
|
||||
#[cold]
|
||||
fn invalid_value(unexp: Unexpected, exp: &Expected) -> Self {
|
||||
Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp))
|
||||
}
|
||||
@@ -226,45 +235,58 @@ macro_rules! declare_error_trait {
|
||||
/// The `exp` argument provides information about what data was being
|
||||
/// expected. For example `exp` might say that a tuple of size 6 was
|
||||
/// expected.
|
||||
#[cold]
|
||||
fn invalid_length(len: usize, exp: &Expected) -> Self {
|
||||
Error::custom(format_args!("invalid length {}, expected {}", len, exp))
|
||||
}
|
||||
|
||||
/// Raised when a `Deserialize` enum type received a variant with an
|
||||
/// unrecognized name.
|
||||
#[cold]
|
||||
fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
|
||||
if expected.is_empty() {
|
||||
Error::custom(format_args!("unknown variant `{}`, there are no variants",
|
||||
variant))
|
||||
Error::custom(format_args!(
|
||||
"unknown variant `{}`, there are no variants",
|
||||
variant
|
||||
))
|
||||
} else {
|
||||
Error::custom(format_args!("unknown variant `{}`, expected {}",
|
||||
variant,
|
||||
OneOf { names: expected }))
|
||||
Error::custom(format_args!(
|
||||
"unknown variant `{}`, expected {}",
|
||||
variant,
|
||||
OneOf { names: expected }
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Raised when a `Deserialize` struct type received a field with an
|
||||
/// unrecognized name.
|
||||
#[cold]
|
||||
fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
|
||||
if expected.is_empty() {
|
||||
Error::custom(format_args!("unknown field `{}`, there are no fields",
|
||||
field))
|
||||
Error::custom(format_args!(
|
||||
"unknown field `{}`, there are no fields",
|
||||
field
|
||||
))
|
||||
} else {
|
||||
Error::custom(format_args!("unknown field `{}`, expected {}",
|
||||
field,
|
||||
OneOf { names: expected }))
|
||||
Error::custom(format_args!(
|
||||
"unknown field `{}`, expected {}",
|
||||
field,
|
||||
OneOf { names: expected }
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Raised when a `Deserialize` struct type expected to receive a required
|
||||
/// field with a particular name but that field was not present in the
|
||||
/// input.
|
||||
#[cold]
|
||||
fn missing_field(field: &'static str) -> Self {
|
||||
Error::custom(format_args!("missing field `{}`", field))
|
||||
}
|
||||
|
||||
/// Raised when a `Deserialize` struct type received more than one of the
|
||||
/// same field.
|
||||
#[cold]
|
||||
fn duplicate_field(field: &'static str) -> Self {
|
||||
Error::custom(format_args!("duplicate field `{}`", field))
|
||||
}
|
||||
@@ -273,7 +295,7 @@ macro_rules! declare_error_trait {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
declare_error_trait!(Error: Sized + error::Error);
|
||||
declare_error_trait!(Error: Sized + StdError);
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
declare_error_trait!(Error: Sized + Debug + Display);
|
||||
@@ -284,7 +306,7 @@ declare_error_trait!(Error: Sized + Debug + Display);
|
||||
/// This is used as an argument to the `invalid_type`, `invalid_value`, and
|
||||
/// `invalid_length` methods of the `Error` trait to build error messages.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use std::fmt;
|
||||
/// #
|
||||
/// # use serde::de::{self, Unexpected, Visitor};
|
||||
@@ -299,7 +321,8 @@ declare_error_trait!(Error: Sized + Debug + Display);
|
||||
/// # }
|
||||
/// #
|
||||
/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||
/// where E: de::Error
|
||||
/// where
|
||||
/// E: de::Error,
|
||||
/// {
|
||||
/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self))
|
||||
/// }
|
||||
@@ -408,7 +431,7 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
||||
/// Within the context of a `Visitor` implementation, the `Visitor` itself
|
||||
/// (`&self`) is an implementation of this trait.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use std::fmt;
|
||||
/// #
|
||||
/// # use serde::de::{self, Unexpected, Visitor};
|
||||
@@ -423,7 +446,8 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
||||
/// # }
|
||||
/// #
|
||||
/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||
/// where E: de::Error
|
||||
/// where
|
||||
/// E: de::Error,
|
||||
/// {
|
||||
/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self))
|
||||
/// }
|
||||
@@ -432,11 +456,12 @@ impl<'a> fmt::Display for Unexpected<'a> {
|
||||
///
|
||||
/// Outside of a `Visitor`, `&"..."` can be used.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{self, Unexpected};
|
||||
/// #
|
||||
/// # fn example<E>() -> Result<(), E>
|
||||
/// # where E: de::Error
|
||||
/// # where
|
||||
/// # E: de::Error,
|
||||
/// # {
|
||||
/// # let v = true;
|
||||
/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer"));
|
||||
@@ -480,7 +505,7 @@ impl<'a> Display for Expected + 'a {
|
||||
///
|
||||
/// Additionally, Serde provides a procedural macro called `serde_derive` to
|
||||
/// automatically generate `Deserialize` implementations for structs and enums
|
||||
/// in your program. See the [codegen section of the manual][codegen] for how to
|
||||
/// in your program. See the [derive section of the manual][derive] for how to
|
||||
/// use this.
|
||||
///
|
||||
/// In rare cases it may be necessary to implement `Deserialize` manually for
|
||||
@@ -493,8 +518,16 @@ impl<'a> Display for Expected + 'a {
|
||||
/// provides an implementation of `Deserialize` for it.
|
||||
///
|
||||
/// [de]: https://docs.serde.rs/serde/de/index.html
|
||||
/// [codegen]: https://serde.rs/codegen.html
|
||||
/// [derive]: https://serde.rs/derive.html
|
||||
/// [impl-deserialize]: https://serde.rs/impl-deserialize.html
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by `Self` when deserialized. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
pub trait Deserialize<'de>: Sized {
|
||||
/// Deserialize this value from the given Serde deserializer.
|
||||
///
|
||||
@@ -544,25 +577,31 @@ pub trait Deserialize<'de>: Sized {
|
||||
/// from the input string, but a `from_reader` function may only deserialize
|
||||
/// owned data.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{Deserialize, DeserializeOwned};
|
||||
/// # use std::io::{Read, Result};
|
||||
/// #
|
||||
/// # trait Ignore {
|
||||
/// fn from_str<'a, T>(s: &'a str) -> Result<T>
|
||||
/// where T: Deserialize<'a>;
|
||||
/// where
|
||||
/// T: Deserialize<'a>;
|
||||
///
|
||||
/// fn from_reader<R, T>(rdr: R) -> Result<T>
|
||||
/// where R: Read,
|
||||
/// T: DeserializeOwned;
|
||||
/// where
|
||||
/// R: Read,
|
||||
/// T: DeserializeOwned;
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The relationship between `Deserialize` and `DeserializeOwned` in trait
|
||||
/// bounds is explained in more detail on the page [Understanding deserializer
|
||||
/// lifetimes].
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
|
||||
impl<T> DeserializeOwned for T
|
||||
where
|
||||
T: for<'de> Deserialize<'de>,
|
||||
{
|
||||
}
|
||||
impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
|
||||
|
||||
/// `DeserializeSeed` is the stateful form of the `Deserialize` trait. If you
|
||||
/// ever find yourself looking for a way to pass data into a `Deserialize` impl,
|
||||
@@ -577,7 +616,7 @@ where
|
||||
///
|
||||
/// The canonical API for stateless deserialization looks like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::Deserialize;
|
||||
/// #
|
||||
/// # enum Error {}
|
||||
@@ -591,7 +630,7 @@ where
|
||||
/// Adjusting an API like this to support stateful deserialization is a matter
|
||||
/// of accepting a seed as input:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::DeserializeSeed;
|
||||
/// #
|
||||
/// # enum Error {}
|
||||
@@ -607,6 +646,14 @@ where
|
||||
/// seed can be appeased by passing `std::marker::PhantomData` as a seed in the
|
||||
/// case of stateless deserialization.
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by `Self::Value` when deserialized. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Suppose we have JSON that looks like `[[1, 2], [3, 4, 5], [6]]` and we need
|
||||
@@ -616,11 +663,11 @@ where
|
||||
/// into it. This requires stateful deserialization using the `DeserializeSeed`
|
||||
/// trait.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// use std::fmt;
|
||||
/// use std::marker::PhantomData;
|
||||
///
|
||||
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, Visitor, SeqAccess};
|
||||
/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor};
|
||||
///
|
||||
/// // A DeserializeSeed implementation that uses stateful deserialization to
|
||||
/// // append array elements onto the end of an existing vector. The preexisting
|
||||
@@ -630,7 +677,8 @@ where
|
||||
/// struct ExtendVec<'a, T: 'a>(&'a mut Vec<T>);
|
||||
///
|
||||
/// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T>
|
||||
/// where T: Deserialize<'de>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// // The return type of the `deserialize` method. This implementation
|
||||
/// // appends onto an existing vector but does not create any new data
|
||||
@@ -638,14 +686,16 @@ where
|
||||
/// type Value = ();
|
||||
///
|
||||
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// // Visitor implementation that will walk an inner array of the JSON
|
||||
/// // input.
|
||||
/// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec<T>);
|
||||
///
|
||||
/// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T>
|
||||
/// where T: Deserialize<'de>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = ();
|
||||
///
|
||||
@@ -654,7 +704,8 @@ where
|
||||
/// }
|
||||
///
|
||||
/// fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error>
|
||||
/// where A: SeqAccess<'de>
|
||||
/// where
|
||||
/// A: SeqAccess<'de>,
|
||||
/// {
|
||||
/// // Visit each element in the inner array and push it onto
|
||||
/// // the existing vector.
|
||||
@@ -673,7 +724,8 @@ where
|
||||
/// struct FlattenedVecVisitor<T>(PhantomData<T>);
|
||||
///
|
||||
/// impl<'de, T> Visitor<'de> for FlattenedVecVisitor<T>
|
||||
/// where T: Deserialize<'de>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// // This Visitor constructs a single Vec<T> to hold the flattened
|
||||
/// // contents of the inner arrays.
|
||||
@@ -684,7 +736,8 @@ where
|
||||
/// }
|
||||
///
|
||||
/// fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error>
|
||||
/// where A: SeqAccess<'de>
|
||||
/// where
|
||||
/// A: SeqAccess<'de>,
|
||||
/// {
|
||||
/// // Create a single Vec to hold the flattened contents.
|
||||
/// let mut vec = Vec::new();
|
||||
@@ -700,7 +753,8 @@ where
|
||||
/// }
|
||||
///
|
||||
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
/// # where D: Deserializer<'de>
|
||||
/// # where
|
||||
/// # D: Deserializer<'de>,
|
||||
/// # {
|
||||
/// let visitor = FlattenedVecVisitor(PhantomData);
|
||||
/// let flattened: Vec<u64> = deserializer.deserialize_seq(visitor)?;
|
||||
@@ -738,10 +792,10 @@ where
|
||||
/// A **data format** that can deserialize any data structure supported by
|
||||
/// Serde.
|
||||
///
|
||||
/// The role of this trait is to define the deserialization half of the Serde
|
||||
/// data model, which is a way to categorize every Rust data type into one of 27
|
||||
/// possible types. Each method of the `Serializer` trait corresponds to one of
|
||||
/// the types of the data model.
|
||||
/// The role of this trait is to define the deserialization half of the [Serde
|
||||
/// data model], which is a way to categorize every Rust data type into one of
|
||||
/// 29 possible types. Each method of the `Deserializer` trait corresponds to one
|
||||
/// of the types of the data model.
|
||||
///
|
||||
/// Implementations of `Deserialize` map themselves into this data model by
|
||||
/// passing to the `Deserializer` a `Visitor` implementation that can receive
|
||||
@@ -749,27 +803,27 @@ where
|
||||
///
|
||||
/// The types that make up the Serde data model are:
|
||||
///
|
||||
/// - **12 primitive types**
|
||||
/// - **14 primitive types**
|
||||
/// - bool
|
||||
/// - i8, i16, i32, i64
|
||||
/// - u8, u16, u32, u64
|
||||
/// - i8, i16, i32, i64, i128
|
||||
/// - u8, u16, u32, u64, u128
|
||||
/// - f32, f64
|
||||
/// - char
|
||||
/// - **string**
|
||||
/// - UTF-8 bytes with a length and no null terminator.
|
||||
/// - When serializing, all strings are handled equally. When deserializing,
|
||||
/// there are three flavors of strings: transient, owned, and borrowed.
|
||||
/// - **byte array** - [u8]
|
||||
/// - Similar to strings, during deserialization byte arrays can be transient,
|
||||
/// owned, or borrowed.
|
||||
/// - **byte array** - \[u8\]
|
||||
/// - Similar to strings, during deserialization byte arrays can be
|
||||
/// transient, owned, or borrowed.
|
||||
/// - **option**
|
||||
/// - Either none or some value.
|
||||
/// - **unit**
|
||||
/// - The type of `()` in Rust. It represents an anonymous value containing no
|
||||
/// data.
|
||||
/// - The type of `()` in Rust. It represents an anonymous value containing
|
||||
/// no data.
|
||||
/// - **unit_struct**
|
||||
/// - For example `struct Unit` or `PhantomData<T>`. It represents a named value
|
||||
/// containing no data.
|
||||
/// - For example `struct Unit` or `PhantomData<T>`. It represents a named
|
||||
/// value containing no data.
|
||||
/// - **unit_variant**
|
||||
/// - For example the `E::A` and `E::B` in `enum E { A, B }`.
|
||||
/// - **newtype_struct**
|
||||
@@ -777,14 +831,15 @@ where
|
||||
/// - **newtype_variant**
|
||||
/// - For example the `E::N` in `enum E { N(u8) }`.
|
||||
/// - **seq**
|
||||
/// - A variably sized heterogeneous sequence of values, for example `Vec<T>` or
|
||||
/// `HashSet<T>`. When serializing, the length may or may not be known before
|
||||
/// iterating through all the data. When deserializing, the length is determined
|
||||
/// by looking at the serialized data.
|
||||
/// - A variably sized heterogeneous sequence of values, for example `Vec<T>`
|
||||
/// or `HashSet<T>`. When serializing, the length may or may not be known
|
||||
/// before iterating through all the data. When deserializing, the length
|
||||
/// is determined by looking at the serialized data.
|
||||
/// - **tuple**
|
||||
/// - A statically sized heterogeneous sequence of values for which the length
|
||||
/// will be known at deserialization time without looking at the serialized
|
||||
/// data, for example `(u8,)` or `(String, u64, Vec<T>)` or `[u64; 10]`.
|
||||
/// - A statically sized heterogeneous sequence of values for which the
|
||||
/// length will be known at deserialization time without looking at the
|
||||
/// serialized data, for example `(u8,)` or `(String, u64, Vec<T>)` or
|
||||
/// `[u64; 10]`.
|
||||
/// - **tuple_struct**
|
||||
/// - A named tuple, for example `struct Rgb(u8, u8, u8)`.
|
||||
/// - **tuple_variant**
|
||||
@@ -792,9 +847,9 @@ where
|
||||
/// - **map**
|
||||
/// - A heterogeneous key-value pairing, for example `BTreeMap<K, V>`.
|
||||
/// - **struct**
|
||||
/// - A heterogeneous key-value pairing in which the keys are strings and will be
|
||||
/// known at deserialization time without looking at the serialized data, for
|
||||
/// example `struct S { r: u8, g: u8, b: u8 }`.
|
||||
/// - A heterogeneous key-value pairing in which the keys are strings and
|
||||
/// will be known at deserialization time without looking at the serialized
|
||||
/// data, for example `struct S { r: u8, g: u8, b: u8 }`.
|
||||
/// - **struct_variant**
|
||||
/// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`.
|
||||
///
|
||||
@@ -809,7 +864,8 @@ where
|
||||
/// type it sees in the input. JSON uses this approach when deserializing
|
||||
/// `serde_json::Value` which is an enum that can represent any JSON
|
||||
/// document. Without knowing what is in a JSON document, we can deserialize
|
||||
/// it to `serde_json::Value` by going through `Deserializer::deserialize_any`.
|
||||
/// it to `serde_json::Value` by going through
|
||||
/// `Deserializer::deserialize_any`.
|
||||
///
|
||||
/// 2. The various `deserialize_*` methods. Non-self-describing formats like
|
||||
/// Bincode need to be told what is in the input in order to deserialize it.
|
||||
@@ -819,10 +875,28 @@ where
|
||||
/// `Deserializer::deserialize_any`.
|
||||
///
|
||||
/// When implementing `Deserialize`, you should avoid relying on
|
||||
/// `Deserializer::deserialize_any` unless you need to be told by the Deserializer
|
||||
/// what type is in the input. Know that relying on `Deserializer::deserialize_any`
|
||||
/// means your data type will be able to deserialize from self-describing
|
||||
/// formats only, ruling out Bincode and many others.
|
||||
/// `Deserializer::deserialize_any` unless you need to be told by the
|
||||
/// Deserializer what type is in the input. Know that relying on
|
||||
/// `Deserializer::deserialize_any` means your data type will be able to
|
||||
/// deserialize from self-describing formats only, ruling out Bincode and many
|
||||
/// others.
|
||||
///
|
||||
/// [Serde data model]: https://serde.rs/data-model.html
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed from the input when deserializing. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website contains example code for
|
||||
/// a basic JSON `Deserializer`.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait Deserializer<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -866,6 +940,20 @@ pub trait Deserializer<'de>: Sized {
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Hint that the `Deserialize` type is expecting an `i128` value.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("i128 is not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Hint that the `Deserialize` type is expecting a `u8` value.
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
@@ -886,6 +974,20 @@ pub trait Deserializer<'de>: Sized {
|
||||
where
|
||||
V: Visitor<'de>;
|
||||
|
||||
serde_if_integer128! {
|
||||
/// Hint that the `Deserialize` type is expecting an `u128` value.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default behavior unconditionally returns an error.
|
||||
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>
|
||||
{
|
||||
let _ = visitor;
|
||||
Err(Error::custom("u128 is not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Hint that the `Deserialize` type is expecting a `f32` value.
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
@@ -1051,7 +1153,7 @@ pub trait Deserializer<'de>: Sized {
|
||||
/// human-readable one and binary formats like Bincode will prefer the
|
||||
/// compact one.
|
||||
///
|
||||
/// ```
|
||||
/// ```edition2018
|
||||
/// # use std::ops::Add;
|
||||
/// # use std::str::FromStr;
|
||||
/// #
|
||||
@@ -1085,7 +1187,8 @@ pub trait Deserializer<'de>: Sized {
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for Timestamp {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where D: Deserializer<'de>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// if deserializer.is_human_readable() {
|
||||
/// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z".
|
||||
@@ -1117,7 +1220,17 @@ pub trait Deserializer<'de>: Sized {
|
||||
|
||||
/// This trait represents a visitor that walks through a deserializer.
|
||||
///
|
||||
/// ```rust
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the requirement for lifetime of data
|
||||
/// that may be borrowed by `Self::Value`. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use std::fmt;
|
||||
/// #
|
||||
/// # use serde::de::{self, Unexpected, Visitor};
|
||||
@@ -1136,7 +1249,8 @@ pub trait Deserializer<'de>: Sized {
|
||||
/// }
|
||||
///
|
||||
/// fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
/// where E: de::Error
|
||||
/// where
|
||||
/// E: de::Error,
|
||||
/// {
|
||||
/// if s.len() >= self.min {
|
||||
/// Ok(s.to_owned())
|
||||
@@ -1157,7 +1271,7 @@ pub trait Visitor<'de>: Sized {
|
||||
/// "an integer between 0 and 64". The message should not be capitalized and
|
||||
/// should not end with a period.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use std::fmt;
|
||||
/// #
|
||||
/// # struct S {
|
||||
@@ -1230,6 +1344,20 @@ pub trait Visitor<'de>: Sized {
|
||||
Err(Error::invalid_type(Unexpected::Signed(v), &self))
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
/// The input contains a `i128`.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default implementation fails with a type error.
|
||||
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = v;
|
||||
Err(Error::invalid_type(Unexpected::Other("i128"), &self))
|
||||
}
|
||||
}
|
||||
|
||||
/// The input contains a `u8`.
|
||||
///
|
||||
/// The default implementation forwards to [`visit_u64`].
|
||||
@@ -1276,6 +1404,20 @@ pub trait Visitor<'de>: Sized {
|
||||
Err(Error::invalid_type(Unexpected::Unsigned(v), &self))
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
/// The input contains a `u128`.
|
||||
///
|
||||
/// This method is available only on Rust compiler versions >=1.26. The
|
||||
/// default implementation fails with a type error.
|
||||
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = v;
|
||||
Err(Error::invalid_type(Unexpected::Other("u128"), &self))
|
||||
}
|
||||
}
|
||||
|
||||
/// The input contains an `f32`.
|
||||
///
|
||||
/// The default implementation forwards to [`visit_f64`].
|
||||
@@ -1507,6 +1649,15 @@ pub trait Visitor<'de>: Sized {
|
||||
let _ = data;
|
||||
Err(Error::invalid_type(Unexpected::Enum, &self))
|
||||
}
|
||||
|
||||
// Used when deserializing a flattened Option field. Not public API.
|
||||
#[doc(hidden)]
|
||||
fn __private_visit_untagged_option<D>(self, _: D) -> Result<Self::Value, ()>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1515,6 +1666,21 @@ pub trait Visitor<'de>: Sized {
|
||||
///
|
||||
/// This is a trait that a `Deserializer` passes to a `Visitor` implementation,
|
||||
/// which deserializes each item in a sequence.
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by deserialized sequence elements. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website demonstrates an
|
||||
/// implementation of `SeqAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait SeqAccess<'de> {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -1582,6 +1748,21 @@ where
|
||||
/// Provides a `Visitor` access to each entry of a map in the input.
|
||||
///
|
||||
/// This is a trait that a `Deserializer` passes to a `Visitor` implementation.
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by deserialized map entries. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website demonstrates an
|
||||
/// implementation of `MapAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait MapAccess<'de> {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -1759,6 +1940,21 @@ where
|
||||
///
|
||||
/// `EnumAccess` is created by the `Deserializer` and passed to the
|
||||
/// `Visitor` in order to identify which variant of an enum to deserialize.
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by the deserialized enum variant. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website demonstrates an
|
||||
/// implementation of `EnumAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait EnumAccess<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization.
|
||||
@@ -1791,6 +1987,21 @@ pub trait EnumAccess<'de>: Sized {
|
||||
/// `VariantAccess` is a visitor that is created by the `Deserializer` and
|
||||
/// passed to the `Deserialize` to deserialize the content of a particular enum
|
||||
/// variant.
|
||||
///
|
||||
/// # Lifetime
|
||||
///
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed by the deserialized enum variant. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example implementation
|
||||
///
|
||||
/// The [example data format] presented on the website demonstrates an
|
||||
/// implementation of `VariantAccess` for a basic JSON data format.
|
||||
///
|
||||
/// [example data format]: https://serde.rs/data-format.html
|
||||
pub trait VariantAccess<'de>: Sized {
|
||||
/// The error type that can be returned if some error occurs during
|
||||
/// deserialization. Must match the error type of our `EnumAccess`.
|
||||
@@ -1801,7 +2012,7 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// If the data contains a different type of variant, the following
|
||||
/// `invalid_type` error should be constructed:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||
/// #
|
||||
/// # struct X;
|
||||
@@ -1816,15 +2027,18 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// }
|
||||
/// #
|
||||
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
|
||||
/// # where T: DeserializeSeed<'de>
|
||||
/// # where
|
||||
/// # T: DeserializeSeed<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -1838,7 +2052,7 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// If the data contains a different type of variant, the following
|
||||
/// `invalid_type` error should be constructed:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||
/// #
|
||||
/// # struct X;
|
||||
@@ -1851,7 +2065,8 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// # }
|
||||
/// #
|
||||
/// fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error>
|
||||
/// where T: DeserializeSeed<'de>
|
||||
/// where
|
||||
/// T: DeserializeSeed<'de>,
|
||||
/// {
|
||||
/// // What the data actually contained; suppose it is a unit variant.
|
||||
/// let unexp = Unexpected::UnitVariant;
|
||||
@@ -1859,11 +2074,13 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// }
|
||||
/// #
|
||||
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -1891,7 +2108,7 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// If the data contains a different type of variant, the following
|
||||
/// `invalid_type` error should be constructed:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||
/// #
|
||||
/// # struct X;
|
||||
@@ -1904,13 +2121,17 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
|
||||
/// # where T: DeserializeSeed<'de>
|
||||
/// # where
|
||||
/// # T: DeserializeSeed<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// fn tuple_variant<V>(self,
|
||||
/// _len: usize,
|
||||
/// _visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor<'de>
|
||||
/// fn tuple_variant<V>(
|
||||
/// self,
|
||||
/// _len: usize,
|
||||
/// _visitor: V,
|
||||
/// ) -> Result<V::Value, Self::Error>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// // What the data actually contained; suppose it is a unit variant.
|
||||
/// let unexp = Unexpected::UnitVariant;
|
||||
@@ -1918,7 +2139,8 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// }
|
||||
/// #
|
||||
/// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -1933,7 +2155,7 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// If the data contains a different type of variant, the following
|
||||
/// `invalid_type` error should be constructed:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected};
|
||||
/// #
|
||||
/// # struct X;
|
||||
@@ -1946,17 +2168,22 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error>
|
||||
/// # where T: DeserializeSeed<'de>
|
||||
/// # where
|
||||
/// # T: DeserializeSeed<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// fn struct_variant<V>(self,
|
||||
/// _fields: &'static [&'static str],
|
||||
/// _visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor<'de>
|
||||
/// fn struct_variant<V>(
|
||||
/// self,
|
||||
/// _fields: &'static [&'static str],
|
||||
/// _visitor: V,
|
||||
/// ) -> Result<V::Value, Self::Error>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// // What the data actually contained; suppose it is a unit variant.
|
||||
/// let unexp = Unexpected::UnitVariant;
|
||||
@@ -1978,14 +2205,20 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// Converts an existing value into a `Deserializer` from which other values can
|
||||
/// be deserialized.
|
||||
///
|
||||
/// ```rust
|
||||
/// #[macro_use]
|
||||
/// extern crate serde_derive;
|
||||
/// # Lifetime
|
||||
///
|
||||
/// extern crate serde;
|
||||
/// The `'de` lifetime of this trait is the lifetime of data that may be
|
||||
/// borrowed from the resulting `Deserializer`. See the page [Understanding
|
||||
/// deserializer lifetimes] for a more detailed explanation of these lifetimes.
|
||||
///
|
||||
/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```edition2018
|
||||
/// use std::str::FromStr;
|
||||
/// use serde::de::{value, Deserialize, IntoDeserializer};
|
||||
/// use serde::Deserialize;
|
||||
/// use serde::de::{value, IntoDeserializer};
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// enum Setting {
|
||||
@@ -2000,8 +2233,6 @@ pub trait VariantAccess<'de>: Sized {
|
||||
/// Self::deserialize(s.into_deserializer())
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
pub trait IntoDeserializer<'de, E: Error = value::Error> {
|
||||
/// The type of the deserializer being converted into.
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
// 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;
|
||||
|
||||
+269
-75
@@ -1,22 +1,10 @@
|
||||
// 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.
|
||||
|
||||
//! Building blocks for deserializing basic values using the `IntoDeserializer`
|
||||
//! trait.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[macro_use]
|
||||
//! extern crate serde_derive;
|
||||
//!
|
||||
//! extern crate serde;
|
||||
//!
|
||||
//! ```edition2018
|
||||
//! use std::str::FromStr;
|
||||
//! use serde::de::{value, Deserialize, IntoDeserializer};
|
||||
//! use serde::Deserialize;
|
||||
//! use serde::de::{value, IntoDeserializer};
|
||||
//!
|
||||
//! #[derive(Deserialize)]
|
||||
//! enum Setting {
|
||||
@@ -31,8 +19,6 @@
|
||||
//! Self::deserialize(s.into_deserializer())
|
||||
//! }
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
|
||||
use lib::*;
|
||||
@@ -44,6 +30,22 @@ use ser;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For structs that contain a PhantomData. We do not want the trait
|
||||
// bound `E: Clone` inferred by derive(Clone).
|
||||
macro_rules! impl_copy_clone {
|
||||
($ty:ident $(<$lifetime:tt>)*) => {
|
||||
impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {}
|
||||
|
||||
impl<$($lifetime,)* E> Clone for $ty<$($lifetime,)* E> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A minimal representation of all possible errors that can occur using the
|
||||
/// `IntoDeserializer` trait.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -58,6 +60,7 @@ type ErrorImpl = ();
|
||||
|
||||
impl de::Error for Error {
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[cold]
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
@@ -68,6 +71,7 @@ impl de::Error for Error {
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
#[cold]
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
@@ -78,6 +82,7 @@ impl de::Error for Error {
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
#[cold]
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
@@ -121,11 +126,13 @@ where
|
||||
}
|
||||
|
||||
/// A deserializer holding a `()`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct UnitDeserializer<E> {
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(UnitDeserializer);
|
||||
|
||||
impl<'de, E> de::Deserializer<'de> for UnitDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -133,9 +140,9 @@ where
|
||||
type Error = E;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf unit unit_struct newtype_struct seq tuple tuple_struct map
|
||||
struct enum identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct enum identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
@@ -155,16 +162,60 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer that cannot be instantiated.
|
||||
#[cfg(feature = "unstable")]
|
||||
pub struct NeverDeserializer<E> {
|
||||
never: !,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for !
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Deserializer = NeverDeserializer<E>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl<'de, E> de::Deserializer<'de> for NeverDeserializer<E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.never
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! primitive_deserializer {
|
||||
($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => {
|
||||
#[doc = "A deserializer holding"]
|
||||
#[doc = $doc]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct $name<E> {
|
||||
value: $ty,
|
||||
marker: PhantomData<E>
|
||||
}
|
||||
|
||||
impl_copy_clone!($name);
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for $ty
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -186,9 +237,9 @@ macro_rules! primitive_deserializer {
|
||||
type Error = E;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct enum identifier ignored_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 deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
@@ -215,13 +266,20 @@ primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32);
|
||||
primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64);
|
||||
primitive_deserializer!(char, "a `char`.", CharDeserializer, visit_char);
|
||||
|
||||
serde_if_integer128! {
|
||||
primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128);
|
||||
primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128);
|
||||
}
|
||||
|
||||
/// A deserializer holding a `u32`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct U32Deserializer<E> {
|
||||
value: u32,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(U32Deserializer);
|
||||
|
||||
impl<'de, E> IntoDeserializer<'de, E> for u32
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -243,9 +301,9 @@ where
|
||||
type Error = E;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
@@ -288,12 +346,14 @@ where
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// A deserializer holding a `&str`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct StrDeserializer<'a, E> {
|
||||
value: &'a str,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(StrDeserializer<'de>);
|
||||
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str
|
||||
where
|
||||
E: de::Error,
|
||||
@@ -336,9 +396,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,12 +421,14 @@ where
|
||||
|
||||
/// A deserializer holding a `&str` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowedStrDeserializer<'de, E> {
|
||||
value: &'de str,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(BorrowedStrDeserializer<'de>);
|
||||
|
||||
impl<'de, E> BorrowedStrDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given string.
|
||||
pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> {
|
||||
@@ -405,9 +467,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,12 +492,22 @@ where
|
||||
|
||||
/// A deserializer holding a `String`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct StringDeserializer<E> {
|
||||
value: String,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<E> Clone for StringDeserializer<E> {
|
||||
fn clone(&self) -> Self {
|
||||
StringDeserializer {
|
||||
value: self.value.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, E> IntoDeserializer<'de, E> for String
|
||||
where
|
||||
@@ -480,9 +552,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,12 +578,22 @@ where
|
||||
|
||||
/// A deserializer holding a `Cow<str>`.
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct CowStrDeserializer<'a, E> {
|
||||
value: Cow<'a, str>,
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'a, E> Clone for CowStrDeserializer<'a, E> {
|
||||
fn clone(&self) -> Self {
|
||||
CowStrDeserializer {
|
||||
value: self.value.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str>
|
||||
where
|
||||
@@ -559,9 +641,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,12 +667,14 @@ where
|
||||
|
||||
/// A deserializer holding a `&[u8]` with a lifetime tied to another
|
||||
/// deserializer.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct BorrowedBytesDeserializer<'de, E> {
|
||||
value: &'de [u8],
|
||||
marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl_copy_clone!(BorrowedBytesDeserializer<'de>);
|
||||
|
||||
impl<'de, E> BorrowedBytesDeserializer<'de, E> {
|
||||
/// Create a new borrowed deserializer from the given byte slice.
|
||||
pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> {
|
||||
@@ -615,9 +699,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct identifier ignored_any enum
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any enum
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,11 +736,8 @@ where
|
||||
{
|
||||
/// Check for remaining elements after passing a `SeqDeserializer` to
|
||||
/// `Visitor::visit_seq`.
|
||||
pub fn end(mut self) -> Result<(), E> {
|
||||
let mut remaining = 0;
|
||||
while self.iter.next().is_some() {
|
||||
remaining += 1;
|
||||
}
|
||||
pub fn end(self) -> Result<(), E> {
|
||||
let remaining = self.iter.count();
|
||||
if remaining == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -688,9 +769,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct enum identifier ignored_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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,9 +884,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct enum identifier ignored_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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,11 +930,8 @@ where
|
||||
{
|
||||
/// Check for remaining elements after passing a `MapDeserializer` to
|
||||
/// `Visitor::visit_map`.
|
||||
pub fn end(mut self) -> Result<(), E> {
|
||||
let mut remaining = 0;
|
||||
while self.iter.next().is_some() {
|
||||
remaining += 1;
|
||||
}
|
||||
pub fn end(self) -> Result<(), E> {
|
||||
let remaining = self.iter.count();
|
||||
if remaining == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -920,9 +998,9 @@ where
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct tuple_struct map struct
|
||||
enum identifier ignored_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 tuple_struct map
|
||||
struct enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,9 +1140,9 @@ where
|
||||
type Error = E;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct tuple_struct map struct
|
||||
enum identifier ignored_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 tuple_struct map
|
||||
struct enum identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
@@ -1209,10 +1287,40 @@ where
|
||||
visitor.visit_map(self.map)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_enum(self)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct enum identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
type Error = A::Error;
|
||||
type Variant = private::MapAsEnum<A>;
|
||||
|
||||
fn variant_seed<T>(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
match self.map.next_key_seed(seed)? {
|
||||
Some(key) => Ok((key, private::map_as_enum(self.map))),
|
||||
None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1221,7 +1329,7 @@ where
|
||||
mod private {
|
||||
use lib::*;
|
||||
|
||||
use de::{self, Unexpected};
|
||||
use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UnitOnly<E> {
|
||||
@@ -1282,6 +1390,92 @@ mod private {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MapAsEnum<A> {
|
||||
map: A,
|
||||
}
|
||||
|
||||
pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> {
|
||||
MapAsEnum { map: map }
|
||||
}
|
||||
|
||||
impl<'de, A> VariantAccess<'de> for MapAsEnum<A>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
type Error = A::Error;
|
||||
|
||||
fn unit_variant(mut self) -> Result<(), Self::Error> {
|
||||
self.map.next_value()
|
||||
}
|
||||
|
||||
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
self.map.next_value_seed(seed)
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.map.next_value_seed(SeedTupleVariant {
|
||||
len: len,
|
||||
visitor: visitor,
|
||||
})
|
||||
}
|
||||
|
||||
fn struct_variant<V>(
|
||||
mut self,
|
||||
_fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.map
|
||||
.next_value_seed(SeedStructVariant { visitor: visitor })
|
||||
}
|
||||
}
|
||||
|
||||
struct SeedTupleVariant<V> {
|
||||
len: usize,
|
||||
visitor: V,
|
||||
}
|
||||
|
||||
impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant<V>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
type Value = V::Value;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_tuple(self.len, self.visitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct SeedStructVariant<V> {
|
||||
visitor: V,
|
||||
}
|
||||
|
||||
impl<'de, V> DeserializeSeed<'de> for SeedStructVariant<V>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
type Value = V::Value;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_map(self.visitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Avoid having to restate the generic types on `MapDeserializer`. The
|
||||
/// `Iterator::Item` contains enough information to figure out K and V.
|
||||
pub trait Pair {
|
||||
|
||||
+6
-8
@@ -1,11 +1,3 @@
|
||||
// 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 use lib::clone::Clone;
|
||||
pub use lib::convert::{From, Into};
|
||||
pub use lib::default::Default;
|
||||
@@ -16,6 +8,12 @@ pub use lib::result::Result::{self, Err, Ok};
|
||||
|
||||
pub use self::string::from_utf8_lossy;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub use lib::{ToString, Vec};
|
||||
|
||||
#[cfg(core_try_from)]
|
||||
pub use lib::convert::TryFrom;
|
||||
|
||||
mod string {
|
||||
use lib::*;
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/// Conditional compilation depending on whether Serde is built with support for
|
||||
/// 128-bit integers.
|
||||
///
|
||||
/// Data formats that wish to support Rust compiler versions older than 1.26
|
||||
/// (or targets that lack 128-bit integers) may place the i128 / u128 methods
|
||||
/// of their Serializer and Deserializer behind this macro.
|
||||
///
|
||||
/// Data formats that require a minimum Rust compiler version of at least 1.26,
|
||||
/// or do not target platforms that lack 128-bit integers, do not need to
|
||||
/// bother with this macro and may assume support for 128-bit integers.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::private::ser::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
/// use serde::{serde_if_integer128, Serializer};
|
||||
///
|
||||
/// impl Serializer for MySerializer {
|
||||
/// type Ok = ();
|
||||
/// type Error = Error;
|
||||
///
|
||||
/// fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// /* ... */
|
||||
///
|
||||
/// serde_if_integer128! {
|
||||
/// fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # serde::__serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant seq
|
||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When Serde is built with support for 128-bit integers, this macro expands
|
||||
/// transparently into just the input tokens.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {
|
||||
/// $($tt)*
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When built without support for 128-bit integers, this macro expands to
|
||||
/// nothing.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {};
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(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)*) => {};
|
||||
}
|
||||
+102
-104
@@ -1,11 +1,3 @@
|
||||
// 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
|
||||
@@ -45,84 +37,104 @@
|
||||
//! used for IPC within the Servo rendering engine.
|
||||
//! - [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.
|
||||
//! - [YAML], a self-proclaimed 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.
|
||||
//! - [RON], a Rusty Object Notation.
|
||||
//! - [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)*
|
||||
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
|
||||
//! definition.
|
||||
//! - [JSON5], A superset of JSON including some productions from ES5.
|
||||
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
|
||||
//! - [URL] query strings, in the x-www-form-urlencoded format.
|
||||
//! - [Envy], a way to deserialize environment variables into Rust structs.
|
||||
//! *(deserialization only)*
|
||||
//! - [Redis], deserialize values from Redis when using [redis-rs].
|
||||
//! *(deserialization only)*
|
||||
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
|
||||
//! Rust structs. *(deserialization only)*
|
||||
//! - [S-expressions], the textual representation of code and data used by the
|
||||
//! Lisp language family.
|
||||
//! - [D-Bus]'s binary wire format.
|
||||
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
|
||||
//!
|
||||
//! [JSON]: https://github.com/serde-rs/json
|
||||
//! [Bincode]: https://github.com/TyOverby/bincode
|
||||
//! [Bincode]: https://github.com/servo/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
|
||||
//! [RON]: https://github.com/ron-rs/ron
|
||||
//! [BSON]: https://github.com/zonyitoo/bson-rs
|
||||
//! [URL]: https://github.com/nox/serde_urlencoded
|
||||
//! [XML]: https://github.com/RReverser/serde-xml-rs
|
||||
//! [Avro]: https://github.com/flavray/avro-rs
|
||||
//! [JSON5]: https://github.com/callum-oakley/json5-rs
|
||||
//! [Postcard]: https://github.com/jamesmunns/postcard
|
||||
//! [URL]: https://docs.rs/serde_qs
|
||||
//! [Envy]: https://github.com/softprops/envy
|
||||
//! [Redis]: https://github.com/OneSignal/serde-redis
|
||||
//! [Envy Store]: https://github.com/softprops/envy-store
|
||||
//! [Cargo]: http://doc.crates.io/manifest.html
|
||||
//! [redis-rs]: https://crates.io/crates/redis
|
||||
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html
|
||||
//! [S-expressions]: https://github.com/rotty/lexpr-rs
|
||||
//! [D-Bus]: https://docs.rs/zvariant
|
||||
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.38")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.116")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// 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(nonzero, specialization))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
// Ignored clippy and clippy_pedantic 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
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
unnested_or_patterns,
|
||||
// not available in our oldest supported compiler
|
||||
checked_conversions,
|
||||
empty_enum,
|
||||
redundant_field_names,
|
||||
redundant_static_lifetimes,
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
cast_possible_truncation,
|
||||
cast_possible_wrap,
|
||||
cast_sign_loss,
|
||||
// things are often more readable this way
|
||||
cast_lossless,
|
||||
module_name_repetitions,
|
||||
option_if_let_else,
|
||||
single_match_else,
|
||||
type_complexity,
|
||||
use_self,
|
||||
zero_prefixed_literal,
|
||||
// correctly used
|
||||
enum_glob_use,
|
||||
wildcard_imports,
|
||||
// not practical
|
||||
needless_pass_by_value,
|
||||
similar_names,
|
||||
too_many_lines,
|
||||
// preference
|
||||
doc_markdown,
|
||||
unseparated_literal_suffix,
|
||||
// false positive
|
||||
needless_doctest_main,
|
||||
// noisy
|
||||
missing_errors_doc,
|
||||
must_use_candidate,
|
||||
)
|
||||
)]
|
||||
// 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.
|
||||
// Rustc lints.
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -130,9 +142,6 @@
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(all(feature = "unstable", feature = "std"))]
|
||||
extern crate core;
|
||||
|
||||
/// 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.
|
||||
@@ -144,7 +153,7 @@ mod lib {
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
pub use self::core::{cmp, iter, mem, ops, slice, str};
|
||||
pub use self::core::{cmp, iter, mem, num, 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};
|
||||
@@ -155,6 +164,7 @@ mod lib {
|
||||
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::ops::Range;
|
||||
pub use self::core::option::{self, Option};
|
||||
pub use self::core::result::{self, Result};
|
||||
|
||||
@@ -166,7 +176,7 @@ mod lib {
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::String;
|
||||
pub use std::string::{String, ToString};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
@@ -179,17 +189,17 @@ mod lib {
|
||||
pub use std::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::rc::Rc;
|
||||
pub use alloc::rc::{Rc, Weak as RcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::rc::Rc;
|
||||
pub use std::rc::{Rc, Weak as RcWeak};
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::arc::Arc;
|
||||
pub use alloc::sync::{Arc, Weak as ArcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::sync::Arc;
|
||||
pub use std::sync::{Arc, Weak as ArcWeak};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
|
||||
@@ -211,14 +221,30 @@ mod lib {
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
pub use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[allow(deprecated)]
|
||||
pub use core::nonzero::{NonZero, Zeroable};
|
||||
#[cfg(all(feature = "std", collections_bound))]
|
||||
pub use std::collections::Bound;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
pub use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
#[cfg(core_reverse)]
|
||||
pub use self::core::cmp::Reverse;
|
||||
|
||||
#[cfg(ops_bound)]
|
||||
pub use self::core::ops::Bound;
|
||||
|
||||
#[cfg(range_inclusive)]
|
||||
pub use self::core::ops::RangeInclusive;
|
||||
|
||||
#[cfg(all(feature = "std", std_atomic))]
|
||||
pub use std::sync::atomic::{
|
||||
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
|
||||
AtomicUsize, Ordering,
|
||||
};
|
||||
#[cfg(all(feature = "std", std_atomic64))]
|
||||
pub use std::sync::atomic::{AtomicI64, AtomicU64};
|
||||
|
||||
#[cfg(any(core_duration, feature = "std"))]
|
||||
pub use self::core::time::Duration;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -226,6 +252,9 @@ mod lib {
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[macro_use]
|
||||
mod integer128;
|
||||
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
|
||||
@@ -242,42 +271,11 @@ pub mod export;
|
||||
#[doc(hidden)]
|
||||
pub mod private;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod std_error;
|
||||
|
||||
// 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.
|
||||
|
||||
+33
-39
@@ -1,11 +1,3 @@
|
||||
// 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
|
||||
// documentation.
|
||||
@@ -19,10 +11,8 @@
|
||||
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
||||
/// trait methods.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
@@ -31,36 +21,34 @@
|
||||
/// # type Error = value::Error;
|
||||
/// #
|
||||
/// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor<'de>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// #[inline]
|
||||
/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor<'de>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// self.deserialize_any(visitor)
|
||||
/// }
|
||||
/// #
|
||||
/// # forward_to_deserialize_any! {
|
||||
/// # i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
/// # byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
/// # 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_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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
@@ -69,7 +57,8 @@
|
||||
/// # type Error = value::Error;
|
||||
/// #
|
||||
/// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor<'de>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// /* ... */
|
||||
/// # let _ = visitor;
|
||||
@@ -77,13 +66,11 @@
|
||||
/// }
|
||||
///
|
||||
/// forward_to_deserialize_any! {
|
||||
/// bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
/// byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
/// 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
|
||||
@@ -91,12 +78,10 @@
|
||||
/// called `V`. A different type parameter and a different lifetime can be
|
||||
/// specified explicitly if necessary.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use std::marker::PhantomData;
|
||||
/// #
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// #
|
||||
/// # struct MyDeserializer<V>(PhantomData<V>);
|
||||
@@ -105,26 +90,25 @@
|
||||
/// # type Error = value::Error;
|
||||
/// #
|
||||
/// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error>
|
||||
/// # where W: Visitor<'q>
|
||||
/// # where
|
||||
/// # W: Visitor<'q>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// forward_to_deserialize_any! {
|
||||
/// <W: Visitor<'q>>
|
||||
/// bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
/// byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
/// map struct enum identifier ignored_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() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`Deserializer`]: trait.Deserializer.html
|
||||
/// [`Visitor`]: de/trait.Visitor.html
|
||||
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! forward_to_deserialize_any {
|
||||
(<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => {
|
||||
$(forward_to_deserialize_any_helper!{$func<$lifetime, $visitor>})*
|
||||
@@ -153,7 +137,7 @@ macro_rules! forward_to_deserialize_any_method {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! forward_to_deserialize_any_helper {
|
||||
(bool<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()}
|
||||
@@ -170,6 +154,11 @@ macro_rules! forward_to_deserialize_any_helper {
|
||||
(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>()}
|
||||
};
|
||||
@@ -182,6 +171,11 @@ macro_rules! forward_to_deserialize_any_helper {
|
||||
(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>()}
|
||||
};
|
||||
|
||||
+857
-137
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,3 @@
|
||||
// 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 {
|
||||
@@ -32,7 +24,7 @@ macro_rules! __private_deserialize {
|
||||
|
||||
/// Used only by Serde doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! __serialize_unimplemented {
|
||||
($($func:ident)*) => {
|
||||
$(
|
||||
@@ -52,7 +44,7 @@ macro_rules! __serialize_unimplemented_method {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! __serialize_unimplemented_helper {
|
||||
(bool) => {
|
||||
__serialize_unimplemented_method!(serialize_bool(bool) -> Ok);
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
// 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;
|
||||
|
||||
+51
-48
@@ -1,18 +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.
|
||||
|
||||
use lib::*;
|
||||
|
||||
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use self::content::{Content, ContentSerializer, SerializeStructVariantAsMapValue,
|
||||
SerializeTupleVariantAsMapValue};
|
||||
use self::content::{
|
||||
Content, ContentSerializer, SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue,
|
||||
};
|
||||
|
||||
/// Used to check that serde(getter) attributes return the expected type.
|
||||
/// Not public API.
|
||||
@@ -408,10 +401,9 @@ mod content {
|
||||
}
|
||||
|
||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||
try!(
|
||||
self.map
|
||||
.serialize_value(&Content::TupleStruct(self.name, self.fields))
|
||||
);
|
||||
try!(self
|
||||
.map
|
||||
.serialize_value(&Content::TupleStruct(self.name, self.fields)));
|
||||
self.map.end()
|
||||
}
|
||||
}
|
||||
@@ -453,10 +445,9 @@ mod content {
|
||||
}
|
||||
|
||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||
try!(
|
||||
self.map
|
||||
.serialize_value(&Content::Struct(self.name, self.fields))
|
||||
);
|
||||
try!(self
|
||||
.map
|
||||
.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||
self.map.end()
|
||||
}
|
||||
}
|
||||
@@ -946,7 +937,8 @@ mod content {
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let key = self.key
|
||||
let key = self
|
||||
.key
|
||||
.take()
|
||||
.expect("serialize_value called before serialize_key");
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
@@ -1040,7 +1032,7 @@ impl<'a, M> FlatMapSerializer<'a, M>
|
||||
where
|
||||
M: SerializeMap + 'a,
|
||||
{
|
||||
fn bad_type(self, what: Unsupported) -> M::Error {
|
||||
fn bad_type(what: Unsupported) -> M::Error {
|
||||
ser::Error::custom(format_args!(
|
||||
"can only flatten structs and maps (got {})",
|
||||
what
|
||||
@@ -1065,78 +1057,78 @@ where
|
||||
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
|
||||
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Boolean))
|
||||
Err(Self::bad_type(Unsupported::Boolean))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
Err(Self::bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
Err(Self::bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
Err(Self::bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Char))
|
||||
Err(Self::bad_type(Unsupported::Char))
|
||||
}
|
||||
|
||||
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::String))
|
||||
Err(Self::bad_type(Unsupported::String))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::ByteArray))
|
||||
Err(Self::bad_type(Unsupported::ByteArray))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Unit))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::UnitStruct))
|
||||
Err(Self::bad_type(Unsupported::UnitStruct))
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
@@ -1145,7 +1137,7 @@ where
|
||||
_: u32,
|
||||
_: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
Err(Self::bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
@@ -1174,11 +1166,11 @@ where
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Sequence))
|
||||
Err(Self::bad_type(Unsupported::Sequence))
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Tuple))
|
||||
Err(Self::bad_type(Unsupported::Tuple))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
@@ -1186,7 +1178,7 @@ where
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::TupleStruct))
|
||||
Err(Self::bad_type(Unsupported::TupleStruct))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
@@ -1196,7 +1188,7 @@ where
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
Err(Self::bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
@@ -1251,6 +1243,18 @@ where
|
||||
self.0.serialize_value(value)
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
||||
&mut self,
|
||||
key: &K,
|
||||
value: &V,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
K: Serialize,
|
||||
V: Serialize,
|
||||
{
|
||||
self.0.serialize_entry(key, value)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -1326,10 +1330,9 @@ where
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
try!(
|
||||
self.map
|
||||
.serialize_value(&Content::Struct(self.name, self.fields))
|
||||
);
|
||||
try!(self
|
||||
.map
|
||||
.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
use lib::*;
|
||||
use ser::{Error, Impossible, Serialize, Serializer};
|
||||
|
||||
impl Error for fmt::Error {
|
||||
fn custom<T: Display>(_msg: T) -> Self {
|
||||
fmt::Error
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! fmt_primitives {
|
||||
($($f:ident: $t:ty,)*) => {
|
||||
$(
|
||||
fn $f(self, v: $t) -> fmt::Result {
|
||||
Display::fmt(&v, self)
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
/// ```edition2018
|
||||
/// use serde::Serialize;
|
||||
/// use std::fmt::{self, Display};
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
/// #[serde(rename_all = "kebab-case")]
|
||||
/// pub enum MessageType {
|
||||
/// StartRequest,
|
||||
/// EndRequest,
|
||||
/// }
|
||||
///
|
||||
/// impl Display for MessageType {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// self.serialize(f)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
impl<'a, 'b> Serializer for &'a mut fmt::Formatter<'b> {
|
||||
type Ok = ();
|
||||
type Error = fmt::Error;
|
||||
type SerializeSeq = Impossible<(), fmt::Error>;
|
||||
type SerializeTuple = Impossible<(), fmt::Error>;
|
||||
type SerializeTupleStruct = Impossible<(), fmt::Error>;
|
||||
type SerializeTupleVariant = Impossible<(), fmt::Error>;
|
||||
type SerializeMap = Impossible<(), fmt::Error>;
|
||||
type SerializeStruct = Impossible<(), fmt::Error>;
|
||||
type SerializeStructVariant = Impossible<(), fmt::Error>;
|
||||
|
||||
fmt_primitives! {
|
||||
serialize_bool: bool,
|
||||
serialize_i8: i8,
|
||||
serialize_i16: i16,
|
||||
serialize_i32: i32,
|
||||
serialize_i64: i64,
|
||||
serialize_u8: u8,
|
||||
serialize_u16: u16,
|
||||
serialize_u32: u32,
|
||||
serialize_u64: u64,
|
||||
serialize_f32: f32,
|
||||
serialize_f64: f64,
|
||||
serialize_char: char,
|
||||
serialize_str: &str,
|
||||
serialize_unit_struct: &'static str,
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
fmt_primitives! {
|
||||
serialize_i128: i128,
|
||||
serialize_u128: u128,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> fmt::Result {
|
||||
Display::fmt(variant, self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Serialize::serialize(value, self)
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _v: &[u8]) -> fmt::Result {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> fmt::Result {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _value: &T) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> fmt::Result {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> fmt::Result
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStruct, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, fmt::Error> {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
|
||||
fn collect_str<T: ?Sized>(self, value: &T) -> fmt::Result
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Display::fmt(value, self)
|
||||
}
|
||||
}
|
||||
+177
-33
@@ -1,17 +1,6 @@
|
||||
// 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 ser::{Serialize, SerializeTuple, Serializer};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use ser::Error;
|
||||
use ser::{Error, Serialize, SerializeTuple, Serializer};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -44,6 +33,11 @@ primitive_impl!(f32, serialize_f32);
|
||||
primitive_impl!(f64, serialize_f64);
|
||||
primitive_impl!(char, serialize_char);
|
||||
|
||||
serde_if_integer128! {
|
||||
primitive_impl!(i128, serialize_i128);
|
||||
primitive_impl!(u128, serialize_u128);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl Serialize for str {
|
||||
@@ -67,6 +61,15 @@ impl Serialize for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for fmt::Arguments<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -157,10 +160,12 @@ macro_rules! array_impls {
|
||||
}
|
||||
}
|
||||
|
||||
array_impls!(01 02 03 04 05 06 07 08 09 10
|
||||
11 12 13 14 15 16 17 18 19 20
|
||||
21 22 23 24 25 26 27 28 29 30
|
||||
31 32);
|
||||
array_impls! {
|
||||
01 02 03 04 05 06 07 08 09 10
|
||||
11 12 13 14 15 16 17 18 19 20
|
||||
21 22 23 24 25 26 27 28 29 30
|
||||
31 32
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -216,8 +221,7 @@ seq_impl!(VecDeque<T>);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<Idx> Serialize for ops::Range<Idx>
|
||||
impl<Idx> Serialize for Range<Idx>
|
||||
where
|
||||
Idx: Serialize,
|
||||
{
|
||||
@@ -235,6 +239,48 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(range_inclusive)]
|
||||
impl<Idx> Serialize for RangeInclusive<Idx>
|
||||
where
|
||||
Idx: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
use super::SerializeStruct;
|
||||
let mut state = try!(serializer.serialize_struct("RangeInclusive", 2));
|
||||
try!(state.serialize_field("start", &self.start()));
|
||||
try!(state.serialize_field("end", &self.end()));
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(ops_bound, collections_bound))]
|
||||
impl<T> Serialize for Bound<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match *self {
|
||||
Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"),
|
||||
Bound::Included(ref value) => {
|
||||
serializer.serialize_newtype_variant("Bound", 1, "Included", value)
|
||||
}
|
||||
Bound::Excluded(ref value) => {
|
||||
serializer.serialize_newtype_variant("Bound", 2, "Excluded", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
impl Serialize for () {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
@@ -245,6 +291,16 @@ impl Serialize for () {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
impl Serialize for ! {
|
||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! tuple_impls {
|
||||
@@ -374,25 +430,45 @@ deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwne
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
#[allow(deprecated)]
|
||||
impl<T> Serialize for NonZero<T>
|
||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<T: ?Sized> Serialize for RcWeak<T>
|
||||
where
|
||||
T: Serialize + Zeroable + Clone,
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.clone().get().serialize(serializer)
|
||||
self.upgrade().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// This impl requires the [`"rc"`] Cargo feature of Serde.
|
||||
///
|
||||
/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc
|
||||
#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))]
|
||||
impl<T: ?Sized> Serialize for ArcWeak<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.upgrade().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! nonzero_integers {
|
||||
( $( $T: ident, )+ ) => {
|
||||
$(
|
||||
#[cfg(feature = "unstable")]
|
||||
impl Serialize for $T {
|
||||
#[cfg(num_nonzero)]
|
||||
impl Serialize for num::$T {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
@@ -405,15 +481,35 @@ macro_rules! nonzero_integers {
|
||||
}
|
||||
|
||||
nonzero_integers! {
|
||||
// Not including signed NonZeroI* since they might be removed
|
||||
NonZeroU8,
|
||||
NonZeroU16,
|
||||
NonZeroU32,
|
||||
NonZeroU64,
|
||||
// FIXME: https://github.com/serde-rs/serde/issues/1136 NonZeroU128,
|
||||
NonZeroUsize,
|
||||
}
|
||||
|
||||
#[cfg(num_nonzero_signed)]
|
||||
nonzero_integers! {
|
||||
NonZeroI8,
|
||||
NonZeroI16,
|
||||
NonZeroI32,
|
||||
NonZeroI64,
|
||||
NonZeroIsize,
|
||||
}
|
||||
|
||||
// Currently 128-bit integers do not work on Emscripten targets so we need an
|
||||
// additional `#[cfg]`
|
||||
serde_if_integer128! {
|
||||
nonzero_integers! {
|
||||
NonZeroU128,
|
||||
}
|
||||
|
||||
#[cfg(num_nonzero_signed)]
|
||||
nonzero_integers! {
|
||||
NonZeroI128,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Serialize for Cell<T>
|
||||
where
|
||||
T: Serialize + Copy,
|
||||
@@ -434,7 +530,10 @@ where
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.borrow().serialize(serializer)
|
||||
match self.try_borrow() {
|
||||
Ok(value) => value.serialize(serializer),
|
||||
Err(_) => Err(S::Error::custom("already mutably borrowed")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +591,7 @@ where
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(any(core_duration, feature = "std"))]
|
||||
impl Serialize for Duration {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
@@ -515,8 +614,9 @@ impl Serialize for SystemTime {
|
||||
S: Serializer,
|
||||
{
|
||||
use super::SerializeStruct;
|
||||
let duration_since_epoch = self.duration_since(UNIX_EPOCH)
|
||||
.expect("SystemTime must be later than UNIX_EPOCH");
|
||||
let duration_since_epoch = self
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map_err(|_| S::Error::custom("SystemTime must be later than UNIX_EPOCH"))?;
|
||||
let mut state = try!(serializer.serialize_struct("SystemTime", 2));
|
||||
try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs()));
|
||||
try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos()));
|
||||
@@ -533,7 +633,7 @@ impl Serialize for SystemTime {
|
||||
#[cfg(feature = "std")]
|
||||
macro_rules! serialize_display_bounded_length {
|
||||
($value:expr, $max:expr, $serializer:expr) => {{
|
||||
let mut buffer: [u8; $max] = unsafe { mem::uninitialized() };
|
||||
let mut buffer = [0u8; $max];
|
||||
let remaining_len = {
|
||||
let mut remaining = &mut buffer[..];
|
||||
write!(remaining, "{}", $value).unwrap();
|
||||
@@ -545,7 +645,7 @@ macro_rules! serialize_display_bounded_length {
|
||||
// write! only provides fmt::Formatter to Display implementations, which
|
||||
// has methods write_str and write_char but no method to write arbitrary
|
||||
// bytes. Therefore `written` must be valid UTF-8.
|
||||
let written_str = unsafe { str::from_utf8_unchecked(written) };
|
||||
let written_str = str::from_utf8(written).expect("must be valid UTF-8");
|
||||
$serializer.serialize_str(written_str)
|
||||
}};
|
||||
}
|
||||
@@ -737,3 +837,47 @@ where
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(core_reverse)]
|
||||
impl<T> Serialize for Reverse<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(all(feature = "std", std_atomic))]
|
||||
macro_rules! atomic_impl {
|
||||
($($ty:ident)*) => {
|
||||
$(
|
||||
impl Serialize for $ty {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.load(Ordering::SeqCst).serialize(serializer)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", std_atomic))]
|
||||
atomic_impl! {
|
||||
AtomicBool
|
||||
AtomicI8 AtomicI16 AtomicI32 AtomicIsize
|
||||
AtomicU8 AtomicU16 AtomicU32 AtomicUsize
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", std_atomic64))]
|
||||
atomic_impl! {
|
||||
AtomicI64 AtomicU64
|
||||
}
|
||||
|
||||
@@ -1,17 +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.
|
||||
|
||||
//! This module contains `Impossible` serializer and its implementations.
|
||||
|
||||
use lib::*;
|
||||
|
||||
use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
|
||||
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.
|
||||
@@ -21,10 +15,7 @@ use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, Serializ
|
||||
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
||||
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::ser::{Serializer, Impossible};
|
||||
/// # use serde::private::ser::Error;
|
||||
/// #
|
||||
@@ -50,14 +41,12 @@ use ser::{self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, Serializ
|
||||
/// }
|
||||
///
|
||||
/// /* other Serializer methods */
|
||||
/// # __serialize_unimplemented! {
|
||||
/// # serde::__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() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`Serializer`]: trait.Serializer.html
|
||||
|
||||
+377
-296
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
use lib::{Debug, Display};
|
||||
|
||||
/// Either a re-export of std::error::Error or a new identical trait, depending
|
||||
/// on whether Serde's "std" feature is enabled.
|
||||
///
|
||||
/// Serde's error traits [`serde::ser::Error`] and [`serde::de::Error`] require
|
||||
/// [`std::error::Error`] as a supertrait, but only when Serde is built with
|
||||
/// "std" enabled. Data formats that don't care about no\_std support should
|
||||
/// generally provide their error types with a `std::error::Error` impl
|
||||
/// directly:
|
||||
///
|
||||
/// ```edition2018
|
||||
/// #[derive(Debug)]
|
||||
/// struct MySerError {...}
|
||||
///
|
||||
/// impl serde::ser::Error for MySerError {...}
|
||||
///
|
||||
/// impl std::fmt::Display for MySerError {...}
|
||||
///
|
||||
/// // We don't support no_std!
|
||||
/// impl std::error::Error for MySerError {}
|
||||
/// ```
|
||||
///
|
||||
/// Data formats that *do* support no\_std may either have a "std" feature of
|
||||
/// their own:
|
||||
///
|
||||
/// ```toml
|
||||
/// [features]
|
||||
/// std = ["serde/std"]
|
||||
/// ```
|
||||
///
|
||||
/// ```edition2018
|
||||
/// #[cfg(feature = "std")]
|
||||
/// impl std::error::Error for MySerError {}
|
||||
/// ```
|
||||
///
|
||||
/// ... or else provide the std Error impl unconditionally via Serde's
|
||||
/// re-export:
|
||||
///
|
||||
/// ```edition2018
|
||||
/// impl serde::ser::StdError for MySerError {}
|
||||
/// ```
|
||||
pub trait Error: Debug + Display {
|
||||
/// The underlying cause of this error, if any.
|
||||
fn source(&self) -> Option<&(Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
+11
-12
@@ -1,18 +1,15 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.38" # remember to update html_root_url
|
||||
version = "1.0.116" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR 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"
|
||||
documentation = "https://serde.rs/derive.html"
|
||||
keywords = ["serde", "serialization", "no_std"]
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
readme = "crates-io.md"
|
||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
@@ -23,10 +20,12 @@ name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "0.3"
|
||||
quote = "0.5"
|
||||
serde_derive_internals = { version = "=0.23.1", default-features = false, path = "../serde_derive_internals" }
|
||||
syn = { version = "0.13", features = ["visit"] }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.33", features = ["visit"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
// The rustc-cfg strings below are *not* public API. Please let us know by
|
||||
// opening a GitHub issue if your build environment requires some way to enable
|
||||
// these cfgs other than by executing our build script.
|
||||
fn main() {
|
||||
let minor = match rustc_minor_version() {
|
||||
Some(minor) => minor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Underscore const names stabilized in Rust 1.37:
|
||||
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
|
||||
if minor >= 37 {
|
||||
println!("cargo:rustc-cfg=underscore_consts");
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_minor_version() -> Option<u32> {
|
||||
let rustc = env::var_os("RUSTC")?;
|
||||
let output = Command::new(rustc).arg("--version").output().ok()?;
|
||||
let version = str::from_utf8(&output.stdout).ok()?;
|
||||
let mut pieces = version.split('.');
|
||||
if pieces.next() != Some("rustc 1") {
|
||||
return None;
|
||||
}
|
||||
pieces.next()?.parse().ok()
|
||||
}
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../crates-io.md
|
||||
+84
-57
@@ -1,11 +1,3 @@
|
||||
// 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;
|
||||
@@ -13,7 +5,7 @@ use syn::punctuated::{Pair, Punctuated};
|
||||
use syn::visit::{self, Visit};
|
||||
|
||||
use internals::ast::{Container, Data};
|
||||
use internals::attr;
|
||||
use internals::{attr, ungroup};
|
||||
|
||||
use proc_macro2::Span;
|
||||
|
||||
@@ -25,8 +17,8 @@ pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
|
||||
params: generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam {
|
||||
.map(|param| match param {
|
||||
syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
|
||||
eq_token: None,
|
||||
default: None,
|
||||
..param.clone()
|
||||
@@ -46,7 +38,7 @@ pub fn with_where_predicates(
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.extend(predicates.into_iter().cloned());
|
||||
.extend(predicates.iter().cloned());
|
||||
generics
|
||||
}
|
||||
|
||||
@@ -55,7 +47,8 @@ pub fn with_where_predicates_from_fields(
|
||||
generics: &syn::Generics,
|
||||
from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
|
||||
) -> syn::Generics {
|
||||
let predicates = cont.data
|
||||
let predicates = cont
|
||||
.data
|
||||
.all_fields()
|
||||
.flat_map(|field| from_field(&field.attrs))
|
||||
.flat_map(|predicates| predicates.to_vec());
|
||||
@@ -65,10 +58,33 @@ pub fn with_where_predicates_from_fields(
|
||||
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(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
|
||||
}
|
||||
|
||||
// Puts the given bound on any generic type parameters that are used in fields
|
||||
// for which filter returns true.
|
||||
//
|
||||
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
|
||||
// For example, the following struct needs the bound `A: Serialize, B:
|
||||
// Serialize`.
|
||||
//
|
||||
// struct S<'b, A, B: 'b, C> {
|
||||
// a: A,
|
||||
@@ -98,8 +114,8 @@ pub fn with_bound(
|
||||
}
|
||||
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 let syn::Type::Path(ty) = ungroup(&field.ty) {
|
||||
if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
|
||||
if self.all_type_params.contains(&t.ident) {
|
||||
self.associated_type_usage.push(ty);
|
||||
}
|
||||
@@ -110,16 +126,16 @@ pub fn with_bound(
|
||||
|
||||
fn visit_path(&mut self, path: &'ast syn::Path) {
|
||||
if let Some(seg) = path.segments.last() {
|
||||
if seg.into_value().ident == "PhantomData" {
|
||||
if seg.ident == "PhantomData" {
|
||||
// Hardcoded exception, because PhantomData<T> implements
|
||||
// Serialize and Deserialize whether or not T implements it.
|
||||
return;
|
||||
}
|
||||
}
|
||||
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);
|
||||
let id = &path.segments[0].ident;
|
||||
if self.all_type_params.contains(id) {
|
||||
self.relevant_type_params.insert(id.clone());
|
||||
}
|
||||
}
|
||||
visit::visit_path(self, path);
|
||||
@@ -134,24 +150,29 @@ pub fn with_bound(
|
||||
fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
|
||||
}
|
||||
|
||||
let all_type_params = generics.type_params().map(|param| param.ident).collect();
|
||||
let all_type_params = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_type_params: 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);
|
||||
match &cont.data {
|
||||
Data::Enum(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) => {
|
||||
}
|
||||
Data::Struct(_, fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visitor.visit_field(field.original);
|
||||
}
|
||||
@@ -162,7 +183,7 @@ pub fn with_bound(
|
||||
let associated_type_usage = visitor.associated_type_usage;
|
||||
let new_predicates = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident)
|
||||
.map(|param| param.ident.clone())
|
||||
.filter(|id| relevant_type_params.contains(id))
|
||||
.map(|id| syn::TypePath {
|
||||
qself: None,
|
||||
@@ -174,15 +195,16 @@ pub fn with_bound(
|
||||
lifetimes: None,
|
||||
// the type parameter that is being bounded e.g. T
|
||||
bounded_ty: syn::Type::Path(bounded_ty),
|
||||
colon_token: Default::default(),
|
||||
colon_token: <Token![:]>::default(),
|
||||
// the bound e.g. Serialize
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})].into_iter()
|
||||
.collect(),
|
||||
})]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
})
|
||||
});
|
||||
|
||||
@@ -207,15 +229,16 @@ pub fn with_self_bound(
|
||||
lifetimes: None,
|
||||
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||
bounded_ty: type_of_item(cont),
|
||||
colon_token: Default::default(),
|
||||
colon_token: <Token![:]>::default(),
|
||||
// the bound e.g. Default
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})].into_iter()
|
||||
.collect(),
|
||||
})]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}));
|
||||
generics
|
||||
}
|
||||
@@ -224,7 +247,7 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
|
||||
let bound = syn::Lifetime::new(lifetime, Span::call_site());
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: bound,
|
||||
lifetime: bound.clone(),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
@@ -232,12 +255,14 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
|
||||
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);
|
||||
match &mut param {
|
||||
syn::GenericParam::Lifetime(param) => {
|
||||
param.bounds.push(bound.clone());
|
||||
}
|
||||
syn::GenericParam::Type(ref mut param) => {
|
||||
param.bounds.push(syn::TypeParamBound::Lifetime(bound));
|
||||
syn::GenericParam::Type(param) => {
|
||||
param
|
||||
.bounds
|
||||
.push(syn::TypeParamBound::Lifetime(bound.clone()));
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
@@ -246,7 +271,7 @@ pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Gen
|
||||
.collect();
|
||||
|
||||
syn::Generics {
|
||||
params: params,
|
||||
params,
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
@@ -257,34 +282,36 @@ fn type_of_item(cont: &Container) -> syn::Type {
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments: vec![syn::PathSegment {
|
||||
ident: cont.ident,
|
||||
ident: cont.ident.clone(),
|
||||
arguments: syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
lt_token: Default::default(),
|
||||
args: cont.generics
|
||||
lt_token: <Token![<]>::default(),
|
||||
args: cont
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| match *param {
|
||||
syn::GenericParam::Type(ref param) => {
|
||||
.map(|param| match param {
|
||||
syn::GenericParam::Type(param) => {
|
||||
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: param.ident.into(),
|
||||
path: param.ident.clone().into(),
|
||||
}))
|
||||
}
|
||||
syn::GenericParam::Lifetime(ref param) => {
|
||||
syn::GenericArgument::Lifetime(param.lifetime)
|
||||
syn::GenericParam::Lifetime(param) => {
|
||||
syn::GenericArgument::Lifetime(param.lifetime.clone())
|
||||
}
|
||||
syn::GenericParam::Const(_) => {
|
||||
panic!("Serde does not support const generics yet");
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
gt_token: Default::default(),
|
||||
gt_token: <Token![>]>::default(),
|
||||
},
|
||||
),
|
||||
}].into_iter()
|
||||
.collect(),
|
||||
}]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+718
-474
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::format_ident;
|
||||
|
||||
use syn;
|
||||
use try;
|
||||
|
||||
pub fn wrap_in_const(
|
||||
serde_path: Option<&syn::Path>,
|
||||
trait_: &str,
|
||||
ty: &Ident,
|
||||
code: TokenStream,
|
||||
) -> TokenStream {
|
||||
let try_replacement = try::replacement();
|
||||
|
||||
let dummy_const = if cfg!(underscore_consts) {
|
||||
format_ident!("_")
|
||||
} else {
|
||||
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
|
||||
};
|
||||
|
||||
let use_serde = match serde_path {
|
||||
Some(path) => quote! {
|
||||
use #path as _serde;
|
||||
},
|
||||
None => quote! {
|
||||
#[allow(rust_2018_idioms, clippy::useless_attribute)]
|
||||
extern crate serde as _serde;
|
||||
},
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||
const #dummy_const: () = {
|
||||
#use_serde
|
||||
#try_replacement
|
||||
#code
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn unraw(ident: &Ident) -> String {
|
||||
// str::trim_start_matches was added in 1.30, trim_left_matches deprecated
|
||||
// in 1.33. We currently support rustc back to 1.15 so we need to continue
|
||||
// to use the deprecated one.
|
||||
ident.to_string().trim_left_matches("r#").to_owned()
|
||||
}
|
||||
@@ -1,20 +1,13 @@
|
||||
// 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 quote::{ToTokens, Tokens};
|
||||
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 {
|
||||
@@ -33,10 +26,10 @@ 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) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => {
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match &self.0 {
|
||||
Fragment::Expr(expr) => expr.to_tokens(out),
|
||||
Fragment::Block(block) => {
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
@@ -46,10 +39,10 @@ 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) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => block.to_tokens(out),
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match &self.0 {
|
||||
Fragment::Expr(expr) => expr.to_tokens(out),
|
||||
Fragment::Block(block) => block.to_tokens(out),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,24 +51,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) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => {
|
||||
fn to_tokens(&self, out: &mut TokenStream) {
|
||||
match &self.0 {
|
||||
Fragment::Expr(expr) => {
|
||||
expr.to_tokens(out);
|
||||
<Token![,]>::default().to_tokens(out);
|
||||
}
|
||||
Fragment::Block(ref block) => {
|
||||
Fragment::Block(block) => {
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Tokens> for Fragment {
|
||||
fn as_ref(&self) -> &Tokens {
|
||||
match *self {
|
||||
Fragment::Expr(ref expr) => expr,
|
||||
Fragment::Block(ref block) => block,
|
||||
impl AsRef<TokenStream> for Fragment {
|
||||
fn as_ref(&self) -> &TokenStream {
|
||||
match self {
|
||||
Fragment::Expr(expr) => expr,
|
||||
Fragment::Block(block) => block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,46 @@
|
||||
// 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.
|
||||
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
|
||||
|
||||
use attr;
|
||||
use check;
|
||||
use internals::attr;
|
||||
use internals::check;
|
||||
use internals::{Ctxt, Derive};
|
||||
use syn;
|
||||
use syn::punctuated::Punctuated;
|
||||
use Ctxt;
|
||||
|
||||
/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`,
|
||||
/// parsed into an internal representation.
|
||||
pub struct Container<'a> {
|
||||
/// The struct or enum name (without generics).
|
||||
pub ident: syn::Ident,
|
||||
/// Attributes on the structure, parsed for Serde.
|
||||
pub attrs: attr::Container,
|
||||
/// The contents of the struct or enum.
|
||||
pub data: Data<'a>,
|
||||
/// Any generics on the struct or enum.
|
||||
pub generics: &'a syn::Generics,
|
||||
/// Original input.
|
||||
pub original: &'a syn::DeriveInput,
|
||||
}
|
||||
|
||||
/// The fields of a struct or enum.
|
||||
///
|
||||
/// Analagous to `syn::Data`.
|
||||
pub enum Data<'a> {
|
||||
Enum(Vec<Variant<'a>>),
|
||||
Struct(Style, Vec<Field<'a>>),
|
||||
}
|
||||
|
||||
/// A variant of an enum.
|
||||
pub struct Variant<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Variant,
|
||||
pub style: Style,
|
||||
pub fields: Vec<Field<'a>>,
|
||||
pub original: &'a syn::Variant,
|
||||
}
|
||||
|
||||
/// A field of a struct.
|
||||
pub struct Field<'a> {
|
||||
pub ident: Option<syn::Ident>,
|
||||
pub member: syn::Member,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Type,
|
||||
pub original: &'a syn::Field,
|
||||
@@ -40,70 +48,85 @@ pub struct Field<'a> {
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Style {
|
||||
/// Named fields.
|
||||
Struct,
|
||||
/// Many unnamed fields.
|
||||
Tuple,
|
||||
/// One unnamed field.
|
||||
Newtype,
|
||||
/// No fields.
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a> Container<'a> {
|
||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
|
||||
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
|
||||
pub fn from_ast(
|
||||
cx: &Ctxt,
|
||||
item: &'a syn::DeriveInput,
|
||||
derive: Derive,
|
||||
) -> Option<Container<'a>> {
|
||||
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 mut data = match &item.data {
|
||||
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
|
||||
syn::Data::Struct(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");
|
||||
cx.error_spanned_by(item, "Serde does not support derive for unions");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
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 {
|
||||
match &mut data {
|
||||
Data::Enum(variants) => {
|
||||
for variant in variants {
|
||||
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
for field in &mut variant.fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field
|
||||
.attrs
|
||||
.rename_by_rules(variant.attrs.rename_all_rules());
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Struct(_, fields) => {
|
||||
for field in fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rule(variant.attrs.rename_all());
|
||||
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
}
|
||||
},
|
||||
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 item = Container {
|
||||
ident: item.ident,
|
||||
attrs: attrs,
|
||||
data: data,
|
||||
let mut item = Container {
|
||||
ident: item.ident.clone(),
|
||||
attrs,
|
||||
data,
|
||||
generics: &item.generics,
|
||||
original: item,
|
||||
};
|
||||
check::check(cx, &item);
|
||||
item
|
||||
check::check(cx, &mut item, derive);
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Data<'a> {
|
||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
||||
match *self {
|
||||
Data::Enum(ref variants) => {
|
||||
match self {
|
||||
Data::Enum(variants) => {
|
||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Data::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
Data::Struct(_, fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,10 +147,11 @@ fn enum_from_ast<'a>(
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||
Variant {
|
||||
ident: variant.ident,
|
||||
attrs: attrs,
|
||||
style: style,
|
||||
fields: fields,
|
||||
ident: variant.ident.clone(),
|
||||
attrs,
|
||||
style,
|
||||
fields,
|
||||
original: variant,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -139,16 +163,16 @@ fn struct_from_ast<'a>(
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match *fields {
|
||||
syn::Fields::Named(ref fields) => (
|
||||
match fields {
|
||||
syn::Fields::Named(fields) => (
|
||||
Style::Struct,
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => (
|
||||
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(ref fields) => (
|
||||
syn::Fields::Unnamed(fields) => (
|
||||
Style::Tuple,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
@@ -166,7 +190,10 @@ fn fields_from_ast<'a>(
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| Field {
|
||||
ident: field.ident,
|
||||
member: match &field.ident {
|
||||
Some(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,
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,5 @@
|
||||
// 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.
|
||||
//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
|
||||
//! case of the source (e.g. `my-field`, `MY_FIELD`).
|
||||
|
||||
// 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)]
|
||||
@@ -14,7 +9,8 @@ use std::str::FromStr;
|
||||
|
||||
use self::RenameRule::*;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
/// The different possible ways to change case of fields in a struct, or variants in an enum.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum RenameRule {
|
||||
/// Don't apply a default rename rule.
|
||||
None,
|
||||
@@ -22,13 +18,16 @@ pub enum RenameRule {
|
||||
LowerCase,
|
||||
/// Rename direct children to "UPPERCASE" style.
|
||||
UPPERCASE,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
|
||||
/// 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.
|
||||
/// 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.
|
||||
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
|
||||
/// used for constants.
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
@@ -37,6 +36,7 @@ pub enum RenameRule {
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
@@ -61,6 +61,7 @@ impl RenameRule {
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply a renaming rule to a struct field, returning the version expected in the source.
|
||||
pub fn apply_to_field(&self, field: &str) -> String {
|
||||
match *self {
|
||||
None | LowerCase | SnakeCase => field.to_owned(),
|
||||
@@ -0,0 +1,420 @@
|
||||
use internals::ast::{Container, Data, Field, Style};
|
||||
use internals::attr::{Identifier, TagType};
|
||||
use internals::{ungroup, 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);
|
||||
check_from_and_try_from(cx, cont);
|
||||
}
|
||||
|
||||
/// 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_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(getter = \"...\")] is not allowed in an enum",
|
||||
);
|
||||
}
|
||||
}
|
||||
Data::Struct(_, _) => {
|
||||
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[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(variants) => {
|
||||
for variant in variants {
|
||||
for field in &variant.fields {
|
||||
check_flatten_field(cx, variant.style, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Struct(style, 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_spanned_by(
|
||||
field.original,
|
||||
"#[serde(flatten)] cannot be used on tuple structs",
|
||||
);
|
||||
}
|
||||
Style::Newtype => {
|
||||
cx.error_spanned_by(
|
||||
field.original,
|
||||
"#[serde(flatten)] cannot be used on newtype structs",
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// The `other` attribute must be used at most once and it must be the last
|
||||
/// variant of an enum.
|
||||
///
|
||||
/// 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(variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for (i, variant) in variants.iter().enumerate() {
|
||||
match (
|
||||
variant.style,
|
||||
cont.attrs.identifier(),
|
||||
variant.attrs.other(),
|
||||
cont.attrs.tag(),
|
||||
) {
|
||||
// The `other` attribute may not be used in a variant_identifier.
|
||||
(_, Identifier::Variant, true, _) => {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[serde(other)] may not be used on a variant identifier",
|
||||
);
|
||||
}
|
||||
|
||||
// Variant with `other` attribute cannot appear in untagged enum
|
||||
(_, Identifier::No, true, &TagType::None) => {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[serde(other)] cannot appear on untagged enum",
|
||||
);
|
||||
}
|
||||
|
||||
// Variant with `other` attribute must be the last one.
|
||||
(Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
|
||||
if i < variants.len() - 1 {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[serde(other)] must be on the last variant",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Variant with `other` attribute must be a unit variant.
|
||||
(_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[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_spanned_by(
|
||||
variant.original,
|
||||
format!("`{}` must be the last variant", variant.ident),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(_, Identifier::Field, false, _) => {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[serde(field_identifier)] may only contain unit variants",
|
||||
);
|
||||
}
|
||||
|
||||
(_, Identifier::Variant, false, _) => {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
"#[serde(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(variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for variant in variants.iter() {
|
||||
if variant.attrs.serialize_with().is_some() {
|
||||
if variant.attrs.skip_serializing() {
|
||||
cx.error_spanned_by(
|
||||
variant.original,
|
||||
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_spanned_by(
|
||||
variant.original,
|
||||
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_spanned_by(
|
||||
variant.original,
|
||||
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_spanned_by(
|
||||
variant.original,
|
||||
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_spanned_by(
|
||||
variant.original,
|
||||
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(variants) => variants,
|
||||
Data::Struct(_, _) => return,
|
||||
};
|
||||
|
||||
let tag = match cont.attrs.tag() {
|
||||
TagType::Internal { tag } => tag.as_str(),
|
||||
TagType::External | TagType::Adjacent { .. } | TagType::None => return,
|
||||
};
|
||||
|
||||
let diagnose_conflict = || {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
format!("variant field name `{}` conflicts with internal tag", tag),
|
||||
)
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
if check_ser && ser_name == tag {
|
||||
diagnose_conflict();
|
||||
return;
|
||||
}
|
||||
|
||||
for de_name in field.attrs.aliases() {
|
||||
if 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() {
|
||||
TagType::Adjacent { tag, content } => (tag, content),
|
||||
TagType::Internal { .. } | TagType::External | TagType::None => return,
|
||||
};
|
||||
|
||||
if type_tag == content_tag {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
format!(
|
||||
"enum tags `{}` for type and content conflict with each other",
|
||||
type_tag
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] is not allowed with #[serde(from = \"...\")]",
|
||||
);
|
||||
}
|
||||
|
||||
if cont.attrs.type_try_from().is_some() {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]",
|
||||
);
|
||||
}
|
||||
|
||||
if cont.attrs.type_into().is_some() {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] is not allowed with #[serde(into = \"...\")]",
|
||||
);
|
||||
}
|
||||
|
||||
let fields = match &mut cont.data {
|
||||
Data::Enum(_) => {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] is not allowed on an enum",
|
||||
);
|
||||
return;
|
||||
}
|
||||
Data::Struct(Style::Unit, _) => {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] is not allowed on a unit struct",
|
||||
);
|
||||
return;
|
||||
}
|
||||
Data::Struct(_, fields) => fields,
|
||||
};
|
||||
|
||||
let mut transparent_field = None;
|
||||
|
||||
for field in fields {
|
||||
if allow_transparent(field, derive) {
|
||||
if transparent_field.is_some() {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[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_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(transparent)] requires at least one field that is not skipped",
|
||||
);
|
||||
}
|
||||
Derive::Deserialize => {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[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(ident) => format!("`{}`", ident),
|
||||
Member::Unnamed(i) => format!("#{}", i.index),
|
||||
}
|
||||
}
|
||||
|
||||
fn allow_transparent(field: &Field, derive: Derive) -> bool {
|
||||
if let Type::Path(ty) = ungroup(&field.ty) {
|
||||
if let Some(seg) = ty.path.segments.last() {
|
||||
if seg.ident == "PhantomData" {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match derive {
|
||||
Derive::Serialize => !field.attrs.skip_serializing(),
|
||||
Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
|
||||
if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() {
|
||||
cx.error_spanned_by(
|
||||
cont.original,
|
||||
"#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
use quote::ToTokens;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::thread;
|
||||
use syn;
|
||||
|
||||
/// A type to collect errors together and format them.
|
||||
///
|
||||
/// Dropping this object will cause a panic. It must be consumed using `check`.
|
||||
///
|
||||
/// References can be shared since this type uses run-time exclusive mut checking.
|
||||
#[derive(Default)]
|
||||
pub struct Ctxt {
|
||||
// The contents will be set to `None` during checking. This is so that checking can be
|
||||
// enforced.
|
||||
errors: RefCell<Option<Vec<syn::Error>>>,
|
||||
}
|
||||
|
||||
impl Ctxt {
|
||||
/// Create a new context object.
|
||||
///
|
||||
/// This object contains no errors, but will still trigger a panic if it is not `check`ed.
|
||||
pub fn new() -> Self {
|
||||
Ctxt {
|
||||
errors: RefCell::new(Some(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an error to the context object with a tokenenizable object.
|
||||
///
|
||||
/// The object is used for spanning in error messages.
|
||||
pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
|
||||
self.errors
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
// Curb monomorphization from generating too many identical methods.
|
||||
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
||||
}
|
||||
|
||||
/// Add one of Syn's parse errors.
|
||||
pub fn syn_error(&self, err: syn::Error) {
|
||||
self.errors.borrow_mut().as_mut().unwrap().push(err);
|
||||
}
|
||||
|
||||
/// Consume this object, producing a formatted error string if there are errors.
|
||||
pub fn check(self) -> Result<(), Vec<syn::Error>> {
|
||||
let errors = self.errors.borrow_mut().take().unwrap();
|
||||
match errors.len() {
|
||||
0 => Ok(()),
|
||||
_ => Err(errors),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Ctxt {
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() && self.errors.borrow().is_some() {
|
||||
panic!("forgot to check for errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use self::ctxt::Ctxt;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
mod symbol;
|
||||
|
||||
use syn::Type;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Derive {
|
||||
Serialize,
|
||||
Deserialize,
|
||||
}
|
||||
|
||||
pub fn ungroup(mut ty: &Type) -> &Type {
|
||||
while let Type::Group(group) = ty {
|
||||
ty = &group.elem;
|
||||
}
|
||||
ty
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
use std::fmt::{self, Display};
|
||||
use syn::{Ident, Path};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Symbol(&'static str);
|
||||
|
||||
pub const ALIAS: Symbol = Symbol("alias");
|
||||
pub const BORROW: Symbol = Symbol("borrow");
|
||||
pub const BOUND: Symbol = Symbol("bound");
|
||||
pub const CONTENT: Symbol = Symbol("content");
|
||||
pub const CRATE: Symbol = Symbol("crate");
|
||||
pub const DEFAULT: Symbol = Symbol("default");
|
||||
pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields");
|
||||
pub const DESERIALIZE: Symbol = Symbol("deserialize");
|
||||
pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with");
|
||||
pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier");
|
||||
pub const FLATTEN: Symbol = Symbol("flatten");
|
||||
pub const FROM: Symbol = Symbol("from");
|
||||
pub const GETTER: Symbol = Symbol("getter");
|
||||
pub const INTO: Symbol = Symbol("into");
|
||||
pub const OTHER: Symbol = Symbol("other");
|
||||
pub const REMOTE: Symbol = Symbol("remote");
|
||||
pub const RENAME: Symbol = Symbol("rename");
|
||||
pub const RENAME_ALL: Symbol = Symbol("rename_all");
|
||||
pub const SERDE: Symbol = Symbol("serde");
|
||||
pub const SERIALIZE: Symbol = Symbol("serialize");
|
||||
pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with");
|
||||
pub const SKIP: Symbol = Symbol("skip");
|
||||
pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing");
|
||||
pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing");
|
||||
pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if");
|
||||
pub const TAG: Symbol = Symbol("tag");
|
||||
pub const TRANSPARENT: Symbol = Symbol("transparent");
|
||||
pub const TRY_FROM: Symbol = Symbol("try_from");
|
||||
pub const UNTAGGED: Symbol = Symbol("untagged");
|
||||
pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier");
|
||||
pub const WITH: Symbol = Symbol("with");
|
||||
|
||||
impl PartialEq<Symbol> for Ident {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
self == word.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<Symbol> for &'a Ident {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
*self == word.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Symbol> for Path {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
self.is_ident(word.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<Symbol> for &'a Path {
|
||||
fn eq(&self, word: &Symbol) -> bool {
|
||||
self.is_ident(word.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Symbol {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(self.0)
|
||||
}
|
||||
}
|
||||
+56
-37
@@ -1,16 +1,7 @@
|
||||
// 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;
|
||||
//! ```edition2018
|
||||
//! # use serde_derive::{Serialize, Deserialize};
|
||||
//! #
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! # struct S;
|
||||
@@ -22,57 +13,85 @@
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.38")]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(enum_variant_names, redundant_field_names, too_many_arguments, used_underscore_binding)
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.116")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
clippy::enum_variant_names,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::too_many_arguments,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::used_underscore_binding,
|
||||
clippy::wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
)]
|
||||
// Ignored clippy_pedantic lints
|
||||
#![allow(
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::checked_conversions,
|
||||
clippy::doc_markdown,
|
||||
clippy::enum_glob_use,
|
||||
clippy::filter_map,
|
||||
clippy::indexing_slicing,
|
||||
clippy::items_after_statements,
|
||||
clippy::match_same_arms,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::option_if_let_else,
|
||||
clippy::similar_names,
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::use_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
// The `quote!` macro requires deep recursion.
|
||||
#![recursion_limit = "512"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate serde_derive_internals as internals;
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
|
||||
mod internals;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::DeriveInput;
|
||||
|
||||
// Quote's default is def_site but it appears call_site is likely to stabilize
|
||||
// before def_site. Thus we try to use only call_site.
|
||||
macro_rules! quote {
|
||||
($($tt:tt)*) => {
|
||||
quote_spanned!($crate::proc_macro2::Span::call_site()=> $($tt)*)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod bound;
|
||||
#[macro_use]
|
||||
mod fragment;
|
||||
|
||||
mod de;
|
||||
mod dummy;
|
||||
mod pretend;
|
||||
mod ser;
|
||||
mod try;
|
||||
|
||||
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match ser::expand_derive_serialize(&input) {
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
ser::expand_derive_serialize(&input)
|
||||
.unwrap_or_else(to_compile_errors)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Deserialize, attributes(serde))]
|
||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
match de::expand_derive_deserialize(&input) {
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
de::expand_derive_deserialize(&input)
|
||||
.unwrap_or_else(to_compile_errors)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
|
||||
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
|
||||
quote!(#(#compile_errors)*)
|
||||
}
|
||||
|
||||
@@ -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(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, 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(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),* })
|
||||
}
|
||||
+351
-146
@@ -1,43 +1,39 @@
|
||||
// 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::Span;
|
||||
use quote::Tokens;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{self, Ident, Index, Member};
|
||||
|
||||
use bound;
|
||||
use dummy;
|
||||
use fragment::{Fragment, Match, Stmts};
|
||||
use internals::ast::{Container, Data, Field, Style, Variant};
|
||||
use internals::{attr, Ctxt};
|
||||
use internals::{attr, Ctxt, Derive};
|
||||
use pretend;
|
||||
|
||||
use std::u32;
|
||||
|
||||
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, String> {
|
||||
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
|
||||
let ctxt = Ctxt::new();
|
||||
let cont = Container::from_ast(&ctxt, input);
|
||||
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
|
||||
Some(cont) => cont,
|
||||
None => return Err(ctxt.check().unwrap_err()),
|
||||
};
|
||||
precondition(&ctxt, &cont);
|
||||
try!(ctxt.check());
|
||||
ctxt.check()?;
|
||||
|
||||
let ident = &cont.ident;
|
||||
let params = Parameters::new(&cont);
|
||||
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::call_site());
|
||||
let body = Stmts(serialize_body(&cont, ¶ms));
|
||||
let serde = cont.attrs.serde_path();
|
||||
|
||||
let impl_block = if let Some(remote) = cont.attrs.remote() {
|
||||
let vis = &input.vis;
|
||||
let fun = quote_spanned!(Span::call_site()=> serialize);
|
||||
let used = pretend::pretend_used(&cont);
|
||||
quote! {
|
||||
impl #impl_generics #ident #ty_generics #where_clause {
|
||||
#vis fn #fun<__S>(__self: &#remote #ty_generics, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: #serde::Serializer,
|
||||
{
|
||||
#used
|
||||
#body
|
||||
}
|
||||
}
|
||||
@@ -45,9 +41,10 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
|
||||
} else {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics _serde::Serialize for #ident #ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: #serde::Serializer,
|
||||
{
|
||||
#body
|
||||
}
|
||||
@@ -55,24 +52,22 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
|
||||
}
|
||||
};
|
||||
|
||||
let generated = quote! {
|
||||
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
|
||||
const #dummy_const: () = {
|
||||
extern crate serde as _serde;
|
||||
#impl_block
|
||||
};
|
||||
};
|
||||
Ok(generated)
|
||||
Ok(dummy::wrap_in_const(
|
||||
cont.attrs.custom_serde_path(),
|
||||
"SERIALIZE",
|
||||
ident,
|
||||
impl_block,
|
||||
))
|
||||
}
|
||||
|
||||
fn precondition(cx: &Ctxt, cont: &Container) {
|
||||
match cont.attrs.identifier() {
|
||||
attr::Identifier::No => {}
|
||||
attr::Identifier::Field => {
|
||||
cx.error("field identifiers cannot be serialized");
|
||||
cx.error_spanned_by(cont.original, "field identifiers cannot be serialized");
|
||||
}
|
||||
attr::Identifier::Variant => {
|
||||
cx.error("variant identifiers cannot be serialized");
|
||||
cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +87,9 @@ struct Parameters {
|
||||
|
||||
/// Type has a `serde(remote = "...")` attribute.
|
||||
is_remote: bool,
|
||||
|
||||
/// Type has a repr(packed) attribute.
|
||||
is_packed: bool,
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
@@ -105,23 +103,26 @@ impl Parameters {
|
||||
|
||||
let this = match cont.attrs.remote() {
|
||||
Some(remote) => remote.clone(),
|
||||
None => cont.ident.into(),
|
||||
None => cont.ident.clone().into(),
|
||||
};
|
||||
|
||||
let is_packed = cont.attrs.is_packed();
|
||||
|
||||
let generics = build_generics(cont);
|
||||
|
||||
Parameters {
|
||||
self_var: self_var,
|
||||
this: this,
|
||||
generics: generics,
|
||||
is_remote: is_remote,
|
||||
self_var,
|
||||
this,
|
||||
generics,
|
||||
is_remote,
|
||||
is_packed,
|
||||
}
|
||||
}
|
||||
|
||||
/// Type name to use in error messages and `&'static str` arguments to
|
||||
/// various Serializer methods.
|
||||
fn type_name(&self) -> &str {
|
||||
self.this.segments.last().unwrap().value().ident.as_ref()
|
||||
fn type_name(&self) -> String {
|
||||
self.this.segments.last().unwrap().ident.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +134,9 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
let generics =
|
||||
bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound);
|
||||
|
||||
let generics =
|
||||
bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound);
|
||||
|
||||
match cont.attrs.ser_bound() {
|
||||
Some(predicates) => bound::with_where_predicates(&generics, predicates),
|
||||
None => bound::with_bound(
|
||||
@@ -145,34 +149,34 @@ fn build_generics(cont: &Container) -> syn::Generics {
|
||||
}
|
||||
|
||||
// Fields with a `skip_serializing` or `serialize_with` attribute, or which
|
||||
// belong to a variant with a `serialize_with` attribute, are not serialized by
|
||||
// us so we do not generate a bound. Fields with a `bound` attribute specify
|
||||
// their own bound so we do not generate one. All other fields may need a `T:
|
||||
// Serialize` bound where T is the type of the field.
|
||||
// belong to a variant with a 'skip_serializing` or `serialize_with` attribute,
|
||||
// are not serialized by us so we do not generate a bound. Fields with a `bound`
|
||||
// attribute specify their own bound so we do not generate one. All other fields
|
||||
// may need a `T: Serialize` bound where T is the type of the field.
|
||||
fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool {
|
||||
!field.skip_serializing() && field.serialize_with().is_none() && field.ser_bound().is_none()
|
||||
&& variant.map_or(true, |variant| variant.serialize_with().is_none())
|
||||
!field.skip_serializing()
|
||||
&& field.serialize_with().is_none()
|
||||
&& field.ser_bound().is_none()
|
||||
&& variant.map_or(true, |variant| {
|
||||
!variant.skip_serializing()
|
||||
&& variant.serialize_with().is_none()
|
||||
&& variant.ser_bound().is_none()
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
if let Some(type_into) = cont.attrs.type_into() {
|
||||
if cont.attrs.transparent() {
|
||||
serialize_transparent(cont, params)
|
||||
} else if let Some(type_into) = cont.attrs.type_into() {
|
||||
serialize_into(params, type_into)
|
||||
} else {
|
||||
match cont.data {
|
||||
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
|
||||
Data::Struct(Style::Struct, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_none()) {
|
||||
panic!("struct has unnamed fields");
|
||||
}
|
||||
serialize_struct(params, fields, &cont.attrs)
|
||||
}
|
||||
Data::Struct(Style::Tuple, ref fields) => {
|
||||
if fields.iter().any(|field| field.ident.is_some()) {
|
||||
panic!("tuple struct has named fields");
|
||||
}
|
||||
match &cont.data {
|
||||
Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs),
|
||||
Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs),
|
||||
Data::Struct(Style::Tuple, fields) => {
|
||||
serialize_tuple_struct(params, fields, &cont.attrs)
|
||||
}
|
||||
Data::Struct(Style::Newtype, ref fields) => {
|
||||
Data::Struct(Style::Newtype, fields) => {
|
||||
serialize_newtype_struct(params, &fields[0], &cont.attrs)
|
||||
}
|
||||
Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
|
||||
@@ -180,6 +184,29 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
|
||||
let fields = match &cont.data {
|
||||
Data::Struct(_, fields) => fields,
|
||||
Data::Enum(_) => unreachable!(),
|
||||
};
|
||||
|
||||
let self_var = ¶ms.self_var;
|
||||
let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap();
|
||||
let member = &transparent_field.member;
|
||||
|
||||
let path = match transparent_field.attrs.serialize_with() {
|
||||
Some(path) => quote!(#path),
|
||||
None => {
|
||||
let span = transparent_field.original.span();
|
||||
quote_spanned!(span=> _serde::Serialize::serialize)
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#path(&#self_var.#member, __serializer)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment {
|
||||
let self_var = ¶ms.self_var;
|
||||
quote_block! {
|
||||
@@ -232,8 +259,28 @@ fn serialize_tuple_struct(
|
||||
serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct);
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let len = serialize_stmts.len();
|
||||
let let_mut = mut_if(len > 0);
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
|
||||
let len = serialized_fields
|
||||
.map(|(i, field)| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let index = syn::Index {
|
||||
index: i as u32,
|
||||
span: Span::call_site(),
|
||||
};
|
||||
let field_expr = get_member(params, field, &Member::Unnamed(index));
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len));
|
||||
@@ -243,7 +290,7 @@ fn serialize_tuple_struct(
|
||||
}
|
||||
|
||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
||||
assert!(fields.len() as u64 <= u64::from(u32::max_value()));
|
||||
|
||||
if cattrs.has_flatten() {
|
||||
serialize_struct_as_map(params, fields, cattrs)
|
||||
@@ -252,6 +299,19 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream {
|
||||
match cattrs.tag() {
|
||||
attr::TagType::Internal { tag } => {
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let func = struct_trait.serialize_field(Span::call_site());
|
||||
quote! {
|
||||
try!(#func(&mut __serde_state, #tag, #type_name));
|
||||
}
|
||||
}
|
||||
_ => quote! {},
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_struct_as_struct(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
@@ -262,26 +322,32 @@ fn serialize_struct_as_struct(
|
||||
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
|
||||
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct);
|
||||
let tag_field_exists = !tag_field.is_empty();
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||
|
||||
let len = serialized_fields
|
||||
.map(|field| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
let field_expr = get_member(params, field, &Member::Named(ident));
|
||||
let field_expr = get_member(params, field, &field.member);
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||
.fold(
|
||||
quote!(#tag_field_exists as usize),
|
||||
|sum, expr| quote!(#sum + #expr),
|
||||
);
|
||||
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len));
|
||||
#tag_field
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeStruct::end(__serde_state)
|
||||
}
|
||||
@@ -295,12 +361,15 @@ fn serialize_struct_as_map(
|
||||
let serialize_fields =
|
||||
serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap);
|
||||
|
||||
let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap);
|
||||
let tag_field_exists = !tag_field.is_empty();
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||
|
||||
let len = if cattrs.has_flatten() {
|
||||
quote!(_serde::export::None)
|
||||
@@ -309,24 +378,27 @@ fn serialize_struct_as_map(
|
||||
.map(|field| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
let field_expr = get_member(params, field, &Member::Named(ident));
|
||||
let field_expr = get_member(params, field, &field.member);
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||
.fold(
|
||||
quote!(#tag_field_exists as usize),
|
||||
|sum, expr| quote!(#sum + #expr),
|
||||
);
|
||||
quote!(_serde::export::Some(#len))
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
||||
#tag_field
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
||||
assert!(variants.len() as u64 <= u64::from(u32::max_value()));
|
||||
|
||||
let self_var = ¶ms.self_var;
|
||||
|
||||
@@ -350,9 +422,9 @@ fn serialize_variant(
|
||||
variant: &Variant,
|
||||
variant_index: u32,
|
||||
cattrs: &attr::Container,
|
||||
) -> Tokens {
|
||||
) -> TokenStream {
|
||||
let this = ¶ms.this;
|
||||
let variant_ident = variant.ident;
|
||||
let variant_ident = &variant.ident;
|
||||
|
||||
if variant.attrs.skip_serializing() {
|
||||
let skipped_msg = format!(
|
||||
@@ -392,28 +464,24 @@ fn serialize_variant(
|
||||
}
|
||||
}
|
||||
Style::Struct => {
|
||||
let fields = variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| f.ident.expect("struct variant has unnamed fields"));
|
||||
let members = variant.fields.iter().map(|f| &f.member);
|
||||
quote! {
|
||||
#this::#variant_ident { #(ref #fields),* }
|
||||
#this::#variant_ident { #(ref #members),* }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let body = Match(match *cattrs.tag() {
|
||||
attr::EnumTag::External => {
|
||||
let body = Match(match cattrs.tag() {
|
||||
attr::TagType::External => {
|
||||
serialize_externally_tagged_variant(params, variant, variant_index, cattrs)
|
||||
}
|
||||
attr::EnumTag::Internal { ref tag } => {
|
||||
attr::TagType::Internal { tag } => {
|
||||
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
||||
}
|
||||
attr::EnumTag::Adjacent {
|
||||
ref tag,
|
||||
ref content,
|
||||
} => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content),
|
||||
attr::EnumTag::None => serialize_untagged_variant(params, variant, cattrs),
|
||||
attr::TagType::Adjacent { tag, content } => {
|
||||
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
|
||||
}
|
||||
attr::TagType::None => serialize_untagged_variant(params, variant, cattrs),
|
||||
});
|
||||
|
||||
quote! {
|
||||
@@ -444,7 +512,7 @@ fn serialize_externally_tagged_variant(
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
_serde::Serializer::serialize_unit_variant(
|
||||
@@ -462,8 +530,10 @@ fn serialize_externally_tagged_variant(
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant);
|
||||
quote_expr! {
|
||||
_serde::Serializer::serialize_newtype_variant(
|
||||
#func(
|
||||
__serializer,
|
||||
#type_name,
|
||||
#variant_index,
|
||||
@@ -474,17 +544,17 @@ fn serialize_externally_tagged_variant(
|
||||
}
|
||||
Style::Tuple => serialize_tuple_variant(
|
||||
TupleVariant::ExternallyTagged {
|
||||
type_name: type_name,
|
||||
variant_index: variant_index,
|
||||
variant_name: variant_name,
|
||||
type_name,
|
||||
variant_index,
|
||||
variant_name,
|
||||
},
|
||||
params,
|
||||
&variant.fields,
|
||||
),
|
||||
Style::Struct => serialize_struct_variant(
|
||||
StructVariant::ExternallyTagged {
|
||||
variant_index: variant_index,
|
||||
variant_name: variant_name,
|
||||
variant_index,
|
||||
variant_name,
|
||||
},
|
||||
params,
|
||||
&variant.fields,
|
||||
@@ -503,7 +573,7 @@ fn serialize_internally_tagged_variant(
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
|
||||
let enum_ident_str = params.type_name();
|
||||
let variant_ident_str = variant.ident.as_ref();
|
||||
let variant_ident_str = variant.ident.to_string();
|
||||
|
||||
if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
@@ -519,7 +589,7 @@ fn serialize_internally_tagged_variant(
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
@@ -536,8 +606,10 @@ fn serialize_internally_tagged_variant(
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> _serde::private::ser::serialize_tagged_newtype);
|
||||
quote_expr! {
|
||||
_serde::private::ser::serialize_tagged_newtype(
|
||||
#func(
|
||||
__serializer,
|
||||
#enum_ident_str,
|
||||
#variant_ident_str,
|
||||
@@ -548,10 +620,7 @@ fn serialize_internally_tagged_variant(
|
||||
}
|
||||
}
|
||||
Style::Struct => serialize_struct_variant(
|
||||
StructVariant::InternallyTagged {
|
||||
tag: tag,
|
||||
variant_name: variant_name,
|
||||
},
|
||||
StructVariant::InternallyTagged { tag, variant_name },
|
||||
params,
|
||||
&variant.fields,
|
||||
&type_name,
|
||||
@@ -577,7 +646,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
_serde::Serialize::serialize(#ser, __serializer)
|
||||
}
|
||||
} else {
|
||||
match variant.style {
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
@@ -594,9 +663,17 @@ fn serialize_adjacently_tagged_variant(
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
}
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field);
|
||||
return quote_block! {
|
||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 2));
|
||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name));
|
||||
try!(#func(
|
||||
&mut __struct, #content, #field_expr));
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
}
|
||||
Style::Tuple => {
|
||||
serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields)
|
||||
@@ -619,20 +696,16 @@ fn serialize_adjacently_tagged_variant(
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
Style::Newtype => vec![Ident::new("__field0", Span::call_site())],
|
||||
Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))],
|
||||
Style::Tuple => (0..variant.fields.len())
|
||||
.map(|i| Ident::new(&format!("__field{}", i), Span::call_site()))
|
||||
.collect(),
|
||||
Style::Struct => variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| f.ident.expect("struct variant has unnamed fields"))
|
||||
.map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site())))
|
||||
.collect(),
|
||||
Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(),
|
||||
};
|
||||
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
let wrapper_generics = if let Style::Unit = variant.style {
|
||||
let wrapper_generics = if fields_ident.is_empty() {
|
||||
params.generics.clone()
|
||||
} else {
|
||||
bound::with_lifetime_bound(¶ms.generics, "'__a")
|
||||
@@ -647,8 +720,11 @@ fn serialize_adjacently_tagged_variant(
|
||||
|
||||
impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
// Elements that have skip_serializing will be unused.
|
||||
#[allow(unused_variables)]
|
||||
let (#(#fields_ident,)*) = self.data;
|
||||
#inner
|
||||
}
|
||||
@@ -679,7 +755,7 @@ fn serialize_untagged_variant(
|
||||
};
|
||||
}
|
||||
|
||||
match variant.style {
|
||||
match effective_style(variant) {
|
||||
Style::Unit => {
|
||||
quote_expr! {
|
||||
_serde::Serializer::serialize_unit(__serializer)
|
||||
@@ -692,8 +768,10 @@ fn serialize_untagged_variant(
|
||||
field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr);
|
||||
}
|
||||
|
||||
let span = field.original.span();
|
||||
let func = quote_spanned!(span=> _serde::Serialize::serialize);
|
||||
quote_expr! {
|
||||
_serde::Serialize::serialize(#field_expr, __serializer)
|
||||
#func(#field_expr, __serializer)
|
||||
}
|
||||
}
|
||||
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
|
||||
@@ -725,8 +803,23 @@ fn serialize_tuple_variant(
|
||||
|
||||
let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait);
|
||||
|
||||
let len = serialize_stmts.len();
|
||||
let let_mut = mut_if(len > 0);
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
|
||||
let len = serialized_fields
|
||||
.map(|(i, field)| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let field_expr = Ident::new(&format!("__field{}", i), Span::call_site());
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||
|
||||
match context {
|
||||
TupleVariant::ExternallyTagged {
|
||||
@@ -775,10 +868,14 @@ fn serialize_struct_variant<'a>(
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
) -> Fragment {
|
||||
if fields.iter().any(|field| field.attrs.flatten()) {
|
||||
return serialize_struct_variant_with_flatten(context, params, fields, name);
|
||||
}
|
||||
|
||||
let struct_trait = match context {
|
||||
StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant),
|
||||
StructVariant::ExternallyTagged { .. } => StructTrait::SerializeStructVariant,
|
||||
StructVariant::InternallyTagged { .. } | StructVariant::Untagged => {
|
||||
(StructTrait::SerializeStruct)
|
||||
StructTrait::SerializeStruct
|
||||
}
|
||||
};
|
||||
|
||||
@@ -793,10 +890,10 @@ fn serialize_struct_variant<'a>(
|
||||
|
||||
let len = serialized_fields
|
||||
.map(|field| {
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
let member = &field.member;
|
||||
|
||||
match field.attrs.skip_serializing_if() {
|
||||
Some(path) => quote!(if #path(#ident) { 0 } else { 1 }),
|
||||
Some(path) => quote!(if #path(#member) { 0 } else { 1 }),
|
||||
None => quote!(1),
|
||||
}
|
||||
})
|
||||
@@ -849,15 +946,102 @@ fn serialize_struct_variant<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_struct_variant_with_flatten<'a>(
|
||||
context: StructVariant<'a>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
name: &str,
|
||||
) -> Fragment {
|
||||
let struct_trait = StructTrait::SerializeMap;
|
||||
let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);
|
||||
|
||||
let mut serialized_fields = fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
|
||||
match context {
|
||||
StructVariant::ExternallyTagged {
|
||||
variant_index,
|
||||
variant_name,
|
||||
} => {
|
||||
let this = ¶ms.this;
|
||||
let fields_ty = fields.iter().map(|f| &f.ty);
|
||||
let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>();
|
||||
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a");
|
||||
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
|
||||
|
||||
quote_block! {
|
||||
struct __EnumFlatten #wrapper_generics #where_clause {
|
||||
data: (#(&'__a #fields_ty,)*),
|
||||
phantom: _serde::export::PhantomData<#this #ty_generics>,
|
||||
}
|
||||
|
||||
impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
let (#(#members,)*) = self.data;
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::export::None));
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
}
|
||||
|
||||
_serde::Serializer::serialize_newtype_variant(
|
||||
__serializer,
|
||||
#name,
|
||||
#variant_index,
|
||||
#variant_name,
|
||||
&__EnumFlatten {
|
||||
data: (#(#members,)*),
|
||||
phantom: _serde::export::PhantomData::<#this #ty_generics>,
|
||||
})
|
||||
}
|
||||
}
|
||||
StructVariant::InternallyTagged { tag, variant_name } => {
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::export::None));
|
||||
try!(_serde::ser::SerializeMap::serialize_entry(
|
||||
&mut __serde_state,
|
||||
#tag,
|
||||
#variant_name,
|
||||
));
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
}
|
||||
StructVariant::Untagged => {
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(
|
||||
__serializer,
|
||||
_serde::export::None));
|
||||
#(#serialize_fields)*
|
||||
_serde::ser::SerializeMap::end(__serde_state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct_visitor(
|
||||
fields: &[Field],
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
tuple_trait: &TupleTrait,
|
||||
) -> Vec<Tokens> {
|
||||
) -> Vec<TokenStream> {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, field)| !field.attrs.skip_serializing())
|
||||
.map(|(i, field)| {
|
||||
let mut field_expr = if is_enum {
|
||||
let id = Ident::new(&format!("__field{}", i), Span::call_site());
|
||||
@@ -901,17 +1085,17 @@ fn serialize_struct_visitor(
|
||||
params: &Parameters,
|
||||
is_enum: bool,
|
||||
struct_trait: &StructTrait,
|
||||
) -> Vec<Tokens> {
|
||||
) -> Vec<TokenStream> {
|
||||
fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.map(|field| {
|
||||
let field_ident = field.ident.expect("struct has unnamed field");
|
||||
let member = &field.member;
|
||||
|
||||
let mut field_expr = if is_enum {
|
||||
quote!(#field_ident)
|
||||
quote!(#member)
|
||||
} else {
|
||||
get_member(params, field, &Member::Named(field_ident))
|
||||
get_member(params, field, &member)
|
||||
};
|
||||
|
||||
let key_expr = field.attrs.name().serialize_name();
|
||||
@@ -927,8 +1111,9 @@ fn serialize_struct_visitor(
|
||||
|
||||
let span = field.original.span();
|
||||
let ser = if field.attrs.flatten() {
|
||||
let func = quote_spanned!(span=> _serde::Serialize::serialize);
|
||||
quote! {
|
||||
try!(_serde::Serialize::serialize(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
|
||||
try!(#func(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state)));
|
||||
}
|
||||
} else {
|
||||
let func = struct_trait.serialize_field(span);
|
||||
@@ -965,8 +1150,8 @@ fn wrap_serialize_field_with(
|
||||
params: &Parameters,
|
||||
field_ty: &syn::Type,
|
||||
serialize_with: &syn::ExprPath,
|
||||
field_expr: &Tokens,
|
||||
) -> Tokens {
|
||||
field_expr: &TokenStream,
|
||||
) -> TokenStream {
|
||||
wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)])
|
||||
}
|
||||
|
||||
@@ -974,16 +1159,18 @@ fn wrap_serialize_variant_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::ExprPath,
|
||||
variant: &Variant,
|
||||
) -> Tokens {
|
||||
) -> TokenStream {
|
||||
let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect();
|
||||
let field_exprs: Vec<_> = variant
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
let id = field
|
||||
.ident
|
||||
.unwrap_or_else(|| Ident::new(&format!("__field{}", i), Span::call_site()));
|
||||
.map(|field| {
|
||||
let id = match &field.member {
|
||||
Member::Named(ident) => ident.clone(),
|
||||
Member::Unnamed(member) => {
|
||||
Ident::new(&format!("__field{}", member.index), Span::call_site())
|
||||
}
|
||||
};
|
||||
quote!(#id)
|
||||
})
|
||||
.collect();
|
||||
@@ -999,8 +1186,8 @@ fn wrap_serialize_with(
|
||||
params: &Parameters,
|
||||
serialize_with: &syn::ExprPath,
|
||||
field_tys: &[&syn::Type],
|
||||
field_exprs: &[Tokens],
|
||||
) -> Tokens {
|
||||
field_exprs: &[TokenStream],
|
||||
) -> TokenStream {
|
||||
let this = ¶ms.this;
|
||||
let (_, ty_generics, where_clause) = params.generics.split_for_impl();
|
||||
|
||||
@@ -1026,7 +1213,8 @@ fn wrap_serialize_with(
|
||||
|
||||
impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause {
|
||||
fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||
where __S: _serde::Serializer
|
||||
where
|
||||
__S: _serde::Serializer,
|
||||
{
|
||||
#serialize_with(#(self.values.#field_access, )* __s)
|
||||
}
|
||||
@@ -1045,7 +1233,7 @@ fn wrap_serialize_with(
|
||||
// _serde::ser::SerializeStruct::end(__serde_state)
|
||||
//
|
||||
// where we want to omit the `mut` to avoid a warning.
|
||||
fn mut_if(is_mut: bool) -> Option<Tokens> {
|
||||
fn mut_if(is_mut: bool) -> Option<TokenStream> {
|
||||
if is_mut {
|
||||
Some(quote!(mut))
|
||||
} else {
|
||||
@@ -1053,12 +1241,22 @@ fn mut_if(is_mut: bool) -> Option<Tokens> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
|
||||
fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream {
|
||||
let self_var = ¶ms.self_var;
|
||||
match (params.is_remote, field.attrs.getter()) {
|
||||
(false, None) => quote_spanned!(Span::call_site()=> &#self_var.#member),
|
||||
(false, None) => {
|
||||
if params.is_packed {
|
||||
quote!(&{#self_var.#member})
|
||||
} else {
|
||||
quote!(&#self_var.#member)
|
||||
}
|
||||
}
|
||||
(true, None) => {
|
||||
let inner = quote_spanned!(Span::call_site()=> &#self_var.#member);
|
||||
let inner = if params.is_packed {
|
||||
quote!(&{#self_var.#member})
|
||||
} else {
|
||||
quote!(&#self_var.#member)
|
||||
};
|
||||
let ty = field.ty;
|
||||
quote!(_serde::private::ser::constrain::<#ty>(#inner))
|
||||
}
|
||||
@@ -1072,6 +1270,13 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
|
||||
}
|
||||
}
|
||||
|
||||
fn effective_style(variant: &Variant) -> Style {
|
||||
match variant.style {
|
||||
Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit,
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
enum StructTrait {
|
||||
SerializeMap,
|
||||
SerializeStruct,
|
||||
@@ -1079,7 +1284,7 @@ enum StructTrait {
|
||||
}
|
||||
|
||||
impl StructTrait {
|
||||
fn serialize_field(&self, span: Span) -> Tokens {
|
||||
fn serialize_field(&self, span: Span) -> TokenStream {
|
||||
match *self {
|
||||
StructTrait::SerializeMap => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
|
||||
@@ -1093,7 +1298,7 @@ impl StructTrait {
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_field(&self, span: Span) -> Option<Tokens> {
|
||||
fn skip_field(&self, span: Span) -> Option<TokenStream> {
|
||||
match *self {
|
||||
StructTrait::SerializeMap => None,
|
||||
StructTrait::SerializeStruct => {
|
||||
@@ -1113,7 +1318,7 @@ enum TupleTrait {
|
||||
}
|
||||
|
||||
impl TupleTrait {
|
||||
fn serialize_element(&self, span: Span) -> Tokens {
|
||||
fn serialize_element(&self, span: Span) -> TokenStream {
|
||||
match *self {
|
||||
TupleTrait::SerializeTuple => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.23.1" # remember to update html_root_url
|
||||
version = "0.25.0" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR 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/"
|
||||
documentation = "https://docs.rs/serde_derive_internals"
|
||||
keywords = ["serde", "serialization"]
|
||||
readme = "README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "0.3"
|
||||
syn = { version = "0.13", default-features = false, features = ["derive", "parsing", "clone-impls"] }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.33", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../README.md
|
||||
@@ -0,0 +1,25 @@
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.25.0")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
cognitive_complexity,
|
||||
redundant_field_names,
|
||||
trivially_copy_pass_by_ref,
|
||||
wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
unnested_or_patterns,
|
||||
)
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro2;
|
||||
extern crate quote;
|
||||
|
||||
#[path = "src/mod.rs"]
|
||||
mod internals;
|
||||
|
||||
pub use internals::*;
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../serde_derive/src/internals/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,278 +0,0 @@
|
||||
// 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 ast::{Container, Data, Style};
|
||||
use attr::{EnumTag, Identifier};
|
||||
use Ctxt;
|
||||
|
||||
/// 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: &Container) {
|
||||
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);
|
||||
}
|
||||
|
||||
/// 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(_) => {
|
||||
if cont.attrs.has_flatten() {
|
||||
cx.error("#[serde(flatten)] cannot be used within enums");
|
||||
}
|
||||
}
|
||||
Data::Struct(style, _) => {
|
||||
for field in cont.data.all_fields() {
|
||||
if !field.attrs.flatten() {
|
||||
continue;
|
||||
}
|
||||
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 (i, field) in variant.fields.iter().enumerate() {
|
||||
let ident = field
|
||||
.ident
|
||||
.as_ref()
|
||||
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
|
||||
|
||||
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, ident
|
||||
));
|
||||
}
|
||||
|
||||
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, ident
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (i, field) in variant.fields.iter().enumerate() {
|
||||
if field.attrs.skip_deserializing() {
|
||||
let ident = field
|
||||
.ident
|
||||
.as_ref()
|
||||
.map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));
|
||||
|
||||
cx.error(format!(
|
||||
"variant `{}` cannot have both #[serde(deserialize_with)] \
|
||||
and a field {} marked with #[serde(skip_deserializing)]",
|
||||
variant.ident, ident
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// 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 {
|
||||
errors: RefCell<Option<Vec<String>>>,
|
||||
}
|
||||
|
||||
impl Ctxt {
|
||||
pub fn new() -> Self {
|
||||
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());
|
||||
}
|
||||
|
||||
pub fn check(self) -> Result<(), String> {
|
||||
let mut errors = self.errors.borrow_mut().take().unwrap();
|
||||
match errors.len() {
|
||||
0 => Ok(()),
|
||||
1 => Err(errors.pop().unwrap()),
|
||||
n => {
|
||||
let mut msg = format!("{} errors:", n);
|
||||
for err in errors {
|
||||
msg.push_str("\n\t# ");
|
||||
msg.push_str(&err);
|
||||
}
|
||||
Err(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Ctxt {
|
||||
fn drop(&mut self) {
|
||||
if !thread::panicking() && self.errors.borrow().is_some() {
|
||||
panic!("forgot to check for errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// 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;
|
||||
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use ctxt::Ctxt;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
@@ -1,22 +1,22 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "1.0.38" # remember to update html_root_url
|
||||
version = "1.0.116" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR 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"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
readme = "crates-io.md"
|
||||
include = ["src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.16", path = "../serde" }
|
||||
serde = { version = "1.0.60", path = "../serde" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0.16", path = "../serde", features = ["rc"] }
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../crates-io.md
|
||||
+30
-69
@@ -1,11 +1,3 @@
|
||||
// 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;
|
||||
@@ -16,16 +8,10 @@ use std::fmt::Debug;
|
||||
|
||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
@@ -41,7 +27,6 @@ use std::fmt::Debug;
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
@@ -53,16 +38,10 @@ where
|
||||
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_ser_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
@@ -78,7 +57,6 @@ where
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||
where
|
||||
@@ -95,18 +73,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that `value` serializes to the given `tokens`, and then yields `error`.
|
||||
/// 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() {
|
||||
/// ```edition2018
|
||||
/// use std::sync::{Arc, Mutex};
|
||||
/// use std::thread;
|
||||
///
|
||||
/// use serde::Serialize;
|
||||
/// use serde_test::{assert_ser_tokens_error, Token};
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
@@ -114,26 +88,27 @@ where
|
||||
/// lock: Arc<Mutex<u32>>,
|
||||
/// }
|
||||
///
|
||||
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
|
||||
/// let lock = example.lock.clone();
|
||||
/// fn main() {
|
||||
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
|
||||
/// let lock = example.lock.clone();
|
||||
///
|
||||
/// let _ = thread::spawn(move || {
|
||||
/// // This thread will acquire the mutex first, unwrapping the result
|
||||
/// // of `lock` because the lock has not been poisoned.
|
||||
/// let _guard = lock.lock().unwrap();
|
||||
/// 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();
|
||||
/// // 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);
|
||||
/// # }
|
||||
/// 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
|
||||
@@ -152,16 +127,10 @@ where
|
||||
|
||||
/// Asserts that the given `tokens` deserialize into `value`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_de_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
@@ -177,7 +146,6 @@ where
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
@@ -212,16 +180,10 @@ where
|
||||
|
||||
/// Asserts that the given `tokens` yield `error` when deserializing.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_de_tokens_error, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// #[serde(deny_unknown_fields)]
|
||||
/// struct S {
|
||||
@@ -236,7 +198,6 @@ where
|
||||
/// ],
|
||||
/// "unknown field `x`, expected `a` or `b`",
|
||||
/// );
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
|
||||
where
|
||||
|
||||
+16
-17
@@ -1,7 +1,9 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
|
||||
use serde::ser::{
|
||||
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
|
||||
SerializeTupleStruct, SerializeTupleVariant,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
@@ -12,19 +14,17 @@ 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;
|
||||
///
|
||||
/// ```edition2018
|
||||
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
/// use serde_test::{Configure, Token, assert_tokens};
|
||||
/// use serde_test::{assert_tokens, Configure, Token};
|
||||
///
|
||||
/// #[derive(Debug, PartialEq)]
|
||||
/// struct Example(u8, u8);
|
||||
///
|
||||
/// impl Serialize for Example {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where S: Serializer,
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// if serializer.is_human_readable() {
|
||||
/// format!("{}.{}", self.0, self.1).serialize(serializer)
|
||||
@@ -36,7 +36,8 @@ pub struct Compact<T: ?Sized>(T);
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for Example {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where D: Deserializer<'de>,
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// use serde::de::Error;
|
||||
/// if deserializer.is_human_readable() {
|
||||
@@ -63,12 +64,7 @@ pub struct Compact<T: ?Sized>(T);
|
||||
/// Token::TupleEnd,
|
||||
/// ],
|
||||
/// );
|
||||
/// assert_tokens(
|
||||
/// &Example(1, 0).readable(),
|
||||
/// &[
|
||||
/// Token::Str("1.0"),
|
||||
/// ],
|
||||
/// );
|
||||
/// assert_tokens(&Example(1, 0).readable(), &[Token::Str("1.0")]);
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Configure {
|
||||
@@ -201,7 +197,7 @@ macro_rules! impl_serializer {
|
||||
$is_human_readable
|
||||
}
|
||||
|
||||
forward_serialize_methods!{
|
||||
forward_serialize_methods! {
|
||||
serialize_bool bool,
|
||||
serialize_i8 i8,
|
||||
serialize_i16 i16,
|
||||
@@ -476,7 +472,10 @@ use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, Varian
|
||||
macro_rules! forward_deserialize_methods {
|
||||
( $wrapper : ident ( $( $name: ident ),* ) ) => {
|
||||
$(
|
||||
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error> where V: Visitor<'de> {
|
||||
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
(self.0).$name($wrapper(visitor))
|
||||
}
|
||||
)*
|
||||
|
||||
+21
-25
@@ -1,14 +1,8 @@
|
||||
// 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::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
|
||||
use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess,
|
||||
SeqAccess, VariantAccess, Visitor};
|
||||
use serde::de::{
|
||||
self, Deserialize, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
|
||||
VariantAccess, Visitor,
|
||||
};
|
||||
|
||||
use error::Error;
|
||||
use token::Token;
|
||||
@@ -95,11 +89,11 @@ impl<'de> Deserializer<'de> {
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = try!(visitor.visit_seq(DeserializerSeqVisitor {
|
||||
let value = visitor.visit_seq(DeserializerSeqVisitor {
|
||||
de: self,
|
||||
len: len,
|
||||
end: end,
|
||||
},));
|
||||
})?;
|
||||
assert_next_token!(self, end);
|
||||
Ok(value)
|
||||
}
|
||||
@@ -113,11 +107,11 @@ impl<'de> Deserializer<'de> {
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = try!(visitor.visit_map(DeserializerMapVisitor {
|
||||
let value = visitor.visit_map(DeserializerMapVisitor {
|
||||
de: self,
|
||||
len: len,
|
||||
end: end,
|
||||
},));
|
||||
})?;
|
||||
assert_next_token!(self, end);
|
||||
Ok(value)
|
||||
}
|
||||
@@ -127,8 +121,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
type Error = Error;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf unit seq map identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf unit seq map identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
|
||||
@@ -251,7 +245,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
|
||||
Token::UnitVariant { name: n, .. }
|
||||
| Token::NewtypeVariant { name: n, .. }
|
||||
| Token::TupleVariant { name: n, .. }
|
||||
| Token::StructVariant { name: n, .. } if name == n =>
|
||||
| Token::StructVariant { name: n, .. }
|
||||
if name == n =>
|
||||
{
|
||||
visitor.visit_enum(DeserializerEnumVisitor { de: self })
|
||||
}
|
||||
@@ -461,11 +456,11 @@ impl<'de, 'a> EnumAccess<'de> for DeserializerEnumVisitor<'a, 'de> {
|
||||
| Token::TupleVariant { variant: v, .. }
|
||||
| Token::StructVariant { variant: v, .. } => {
|
||||
let de = v.into_deserializer();
|
||||
let value = try!(seed.deserialize(de));
|
||||
let value = seed.deserialize(de)?;
|
||||
Ok((value, self))
|
||||
}
|
||||
_ => {
|
||||
let value = try!(seed.deserialize(&mut *self.de));
|
||||
let value = seed.deserialize(&mut *self.de)?;
|
||||
Ok((value, self))
|
||||
}
|
||||
}
|
||||
@@ -597,7 +592,8 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
|
||||
{
|
||||
match self.variant.take() {
|
||||
Some(Token::Str(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
|
||||
Some(Token::Bytes(variant)) => seed.deserialize(BytesDeserializer { value: variant })
|
||||
Some(Token::Bytes(variant)) => seed
|
||||
.deserialize(BytesDeserializer { value: variant })
|
||||
.map(Some),
|
||||
Some(Token::U32(variant)) => seed.deserialize(variant.into_deserializer()).map(Some),
|
||||
Some(other) => unexpected!(other),
|
||||
@@ -617,7 +613,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
|
||||
len: None,
|
||||
end: Token::TupleVariantEnd,
|
||||
};
|
||||
try!(seed.deserialize(SeqAccessDeserializer::new(visitor)))
|
||||
seed.deserialize(SeqAccessDeserializer::new(visitor))?
|
||||
};
|
||||
assert_next_token!(self.de, Token::TupleVariantEnd);
|
||||
Ok(value)
|
||||
@@ -629,7 +625,7 @@ impl<'de, 'a> MapAccess<'de> for EnumMapVisitor<'a, 'de> {
|
||||
len: None,
|
||||
end: Token::StructVariantEnd,
|
||||
};
|
||||
try!(seed.deserialize(MapAccessDeserializer::new(visitor)))
|
||||
seed.deserialize(MapAccessDeserializer::new(visitor))?
|
||||
};
|
||||
assert_next_token!(self.de, Token::StructVariantEnd);
|
||||
Ok(value)
|
||||
@@ -654,8 +650,8 @@ impl<'de> de::Deserializer<'de> for BytesDeserializer {
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
|
||||
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct
|
||||
map struct enum identifier ignored_any
|
||||
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
tuple_struct map struct enum identifier ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
// 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};
|
||||
|
||||
|
||||
+34
-37
@@ -1,11 +1,3 @@
|
||||
// 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`].
|
||||
//!
|
||||
@@ -32,19 +24,10 @@
|
||||
//!
|
||||
//! [`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;
|
||||
//! ```edition2018
|
||||
//! # const IGNORE: &str = stringify! {
|
||||
//! use linked_hash_map::LinkedHashMap;
|
||||
//! # }
|
||||
//!
|
||||
//! extern crate serde_test;
|
||||
//! # };
|
||||
//! use serde_test::{Token, assert_tokens};
|
||||
//!
|
||||
//! # use std::fmt;
|
||||
@@ -68,11 +51,13 @@
|
||||
//! # }
|
||||
//! #
|
||||
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
|
||||
//! # where K: Serialize,
|
||||
//! # V: Serialize
|
||||
//! # where
|
||||
//! # K: Serialize,
|
||||
//! # V: Serialize,
|
||||
//! # {
|
||||
//! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
//! # where S: Serializer
|
||||
//! # where
|
||||
//! # S: Serializer,
|
||||
//! # {
|
||||
//! # let mut map = serializer.serialize_map(Some(self.0.len()))?;
|
||||
//! # for &(ref k, ref v) in &self.0 {
|
||||
@@ -85,8 +70,9 @@
|
||||
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
|
||||
//! #
|
||||
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
|
||||
//! # where K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>
|
||||
//! # where
|
||||
//! # K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>,
|
||||
//! # {
|
||||
//! # type Value = LinkedHashMap<K, V>;
|
||||
//! #
|
||||
@@ -95,7 +81,8 @@
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
//! # where M: MapAccess<'de>
|
||||
//! # where
|
||||
//! # M: MapAccess<'de>,
|
||||
//! # {
|
||||
//! # let mut map = LinkedHashMap::new();
|
||||
//! # while let Some((key, value)) = access.next_entry()? {
|
||||
@@ -106,11 +93,13 @@
|
||||
//! # }
|
||||
//! #
|
||||
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
|
||||
//! # where K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>
|
||||
//! # where
|
||||
//! # K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>,
|
||||
//! # {
|
||||
//! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
//! # where D: Deserializer<'de>
|
||||
//! # where
|
||||
//! # D: Deserializer<'de>,
|
||||
//! # {
|
||||
//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
|
||||
//! # }
|
||||
@@ -155,16 +144,22 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.38")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.116")]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Whitelisted clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
|
||||
// Whitelisted clippy_pedantic lints
|
||||
// Ignored clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
|
||||
// Ignored 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
|
||||
empty_line_after_outer_attr,
|
||||
missing_docs_in_private_items,
|
||||
module_name_repetitions,
|
||||
must_use_candidate,
|
||||
redundant_field_names,
|
||||
use_debug,
|
||||
use_self
|
||||
)
|
||||
)]
|
||||
|
||||
@@ -179,8 +174,10 @@ 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 assert::{
|
||||
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_tokens,
|
||||
};
|
||||
pub use token::Token;
|
||||
|
||||
pub use configure::{Compact, Configure, Readable};
|
||||
|
||||
+7
-14
@@ -1,17 +1,10 @@
|
||||
// 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;
|
||||
|
||||
/// A `Serializer` that ensures that a value serializes to a given list of tokens.
|
||||
/// A `Serializer` that ensures that a value serializes to a given list of
|
||||
/// tokens.
|
||||
#[derive(Debug)]
|
||||
pub struct Serializer<'a> {
|
||||
tokens: &'a [Token],
|
||||
@@ -45,7 +38,7 @@ macro_rules! assert_next_token {
|
||||
($ser:expr, $expected:ident($v:expr)) => {
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!("{}({:?})", stringify!($expected), $v),
|
||||
format_args!(concat!(stringify!($expected), "({:?})"), $v),
|
||||
Token::$expected(v),
|
||||
v == $v
|
||||
);
|
||||
@@ -56,13 +49,13 @@ macro_rules! assert_next_token {
|
||||
use std::fmt::Write;
|
||||
let mut buffer = String::new();
|
||||
$(
|
||||
write!(&mut buffer, "{}: {:?}, ", stringify!($k), $k).unwrap();
|
||||
write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap();
|
||||
)*
|
||||
buffer
|
||||
};
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!("{} {{ {}}}", stringify!($expected), field_format()),
|
||||
format_args!(concat!(stringify!($expected), " {{ {}}}"), field_format()),
|
||||
Token::$expected { $($k),* },
|
||||
($($k,)*) == compare
|
||||
);
|
||||
@@ -434,7 +427,7 @@ impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> {
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
try!(key.serialize(&mut **self));
|
||||
key.serialize(&mut **self)?;
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
@@ -456,7 +449,7 @@ impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> {
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
try!(key.serialize(&mut *self.ser));
|
||||
key.serialize(&mut *self.ser)?;
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
|
||||
+39
-92
@@ -1,18 +1,10 @@
|
||||
// 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
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&true, &[Token::Bool(true)]);
|
||||
@@ -21,7 +13,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `i8`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i8, &[Token::I8(0)]);
|
||||
@@ -30,7 +22,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `i16`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i16, &[Token::I16(0)]);
|
||||
@@ -39,7 +31,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `i32`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i32, &[Token::I32(0)]);
|
||||
@@ -48,7 +40,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `i64`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i64, &[Token::I64(0)]);
|
||||
@@ -57,7 +49,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `u8`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u8, &[Token::U8(0)]);
|
||||
@@ -66,7 +58,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `u16`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u16, &[Token::U16(0)]);
|
||||
@@ -75,7 +67,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `u32`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u32, &[Token::U32(0)]);
|
||||
@@ -84,7 +76,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `u64`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u64, &[Token::U64(0)]);
|
||||
@@ -93,7 +85,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `f32`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
|
||||
@@ -102,7 +94,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `f64`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
|
||||
@@ -111,7 +103,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `char`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&'\n', &[Token::Char('\n')]);
|
||||
@@ -120,7 +112,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `str`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s = String::from("transient");
|
||||
@@ -130,7 +122,7 @@ pub enum Token {
|
||||
|
||||
/// A borrowed `str`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s: &str = "borrowed";
|
||||
@@ -140,7 +132,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `String`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s = String::from("owned");
|
||||
@@ -159,7 +151,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `Option<T>` containing none.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let opt = None::<char>;
|
||||
@@ -171,7 +163,7 @@ pub enum Token {
|
||||
///
|
||||
/// The tokens of the value follow after this header.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let opt = Some('c');
|
||||
@@ -184,7 +176,7 @@ pub enum Token {
|
||||
|
||||
/// A serialized `()`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&(), &[Token::Unit]);
|
||||
@@ -193,13 +185,8 @@ pub enum Token {
|
||||
|
||||
/// A serialized unit struct of the given name.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -213,13 +200,8 @@ pub enum Token {
|
||||
|
||||
/// A unit variant of an enum.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -241,13 +223,8 @@ pub enum Token {
|
||||
///
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -267,13 +244,8 @@ pub enum Token {
|
||||
///
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -299,7 +271,7 @@ pub enum Token {
|
||||
/// After this header are the elements of the sequence, followed by
|
||||
/// `SeqEnd`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let vec = vec!['a', 'b', 'c'];
|
||||
@@ -320,7 +292,7 @@ pub enum Token {
|
||||
///
|
||||
/// After this header are the elements of the tuple, followed by `TupleEnd`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let tuple = ('a', 100);
|
||||
@@ -341,13 +313,8 @@ pub enum Token {
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -373,13 +340,8 @@ pub enum Token {
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -410,7 +372,7 @@ pub enum Token {
|
||||
///
|
||||
/// After this header are the entries of the map, followed by `MapEnd`.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// use std::collections::BTreeMap;
|
||||
@@ -437,13 +399,8 @@ pub enum Token {
|
||||
///
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -474,13 +431,8 @@ pub enum Token {
|
||||
/// 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;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
@@ -509,13 +461,8 @@ pub enum Token {
|
||||
|
||||
/// The header to an enum of the given name.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use]
|
||||
/// # extern crate serde_derive;
|
||||
/// #
|
||||
/// # extern crate serde;
|
||||
/// # extern crate serde_test;
|
||||
/// #
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
|
||||
+14
-7
@@ -2,18 +2,25 @@
|
||||
name = "serde_test_suite"
|
||||
version = "0.0.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
unstable = ["serde/unstable", "compiletest_rs"]
|
||||
expandtest = []
|
||||
unstable = ["serde/unstable"]
|
||||
|
||||
[dependencies]
|
||||
serde = { path = "../serde" }
|
||||
|
||||
[build-dependencies]
|
||||
toolchain_find = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
proc-macro2 = "0.3"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde", features = ["rc"] }
|
||||
macrotest = "=1.0.0"
|
||||
rustversion = "1.0"
|
||||
serde = { path = "../serde", features = ["rc", "derive"] }
|
||||
serde_derive = { path = "../serde_derive", features = ["deserialize_in_place"] }
|
||||
serde_test = { path = "../serde_test" }
|
||||
|
||||
[dependencies]
|
||||
compiletest_rs = { version = "0.3", optional = true }
|
||||
trybuild = "1.0"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use std::process::{Command, ExitStatus, Stdio};
|
||||
|
||||
fn has_cargo_expand() -> bool {
|
||||
let cargo_expand = if cfg!(windows) {
|
||||
"cargo-expand.exe"
|
||||
} else {
|
||||
"cargo-expand"
|
||||
};
|
||||
|
||||
Command::new(cargo_expand)
|
||||
.arg("--version")
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.as_ref()
|
||||
.map(ExitStatus::success)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn has_rustfmt() -> bool {
|
||||
toolchain_find::find_installed_component("rustfmt").is_some()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if cfg!(feature = "expandtest") && has_cargo_expand() && has_rustfmt() {
|
||||
println!("cargo:rustc-cfg=expandtest");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
[package]
|
||||
name = "serde_test_suite_deps"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
publish = false
|
||||
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
serde = { path = "../../serde" }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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. ===]
|
||||
#![====================================================*/)]
|
||||
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "serde_derive_tests_no_std"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "0.2", default-features = false }
|
||||
serde = { path = "../../serde", default-features = false }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
serde = { path = "../../serde", default-features = false, features = ["derive"] }
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
// 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;
|
||||
|
||||
#[start]
|
||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
0
|
||||
@@ -20,13 +10,8 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_eh_personality() {}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_begin_panic(
|
||||
_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32,
|
||||
) -> ! {
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe {
|
||||
libc::abort();
|
||||
}
|
||||
@@ -34,8 +19,7 @@ pub extern "C" fn rust_begin_panic(
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Unit;
|
||||
|
||||
@@ -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) = 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())
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,21 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,21 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,20 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,16 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,24 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,24 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,24 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,16 +0,0 @@
|
||||
// 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() {}
|
||||
@@ -1,21 +0,0 @@
|
||||
// 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 within enums
|
||||
enum Foo {
|
||||
A {
|
||||
#[serde(flatten)]
|
||||
fields: HashMap<String, String>,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,22 +0,0 @@
|
||||
// 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,16 +0,0 @@
|
||||
// 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
|
||||
#[serde(default)] //~^ HELP: #[serde(default)] can only be used on structs
|
||||
enum E {
|
||||
S { f: u8 },
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// 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
|
||||
#[serde(default)] //~^ HELP: #[serde(default)] can only be used on structs
|
||||
struct T(u8, u8);
|
||||
|
||||
fn main() { }
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename="x", serialize="y")] //~^^ HELP: unknown serde field attribute `serialize`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,19 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename="x")]
|
||||
#[serde(rename(deserialize="y"))] //~^^^ HELP: duplicate serde attribute `rename`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename(serialize="x"), rename(serialize="y"))] //~^^ HELP: duplicate serde attribute `rename`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,19 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename(serialize="x"))]
|
||||
#[serde(rename="y")] //~^^^ HELP: duplicate serde attribute `rename`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename(serialize="x", serialize="y"))] //~^^ HELP: duplicate serde attribute `rename`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,19 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(rename(serialize="x"))]
|
||||
#[serde(rename(serialize="y"))] //~^^^ HELP: duplicate serde attribute `rename`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -1,18 +0,0 @@
|
||||
// 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(Serialize)] //~ ERROR: proc-macro derive panicked
|
||||
struct S {
|
||||
#[serde(with = "w", serialize_with = "s")] //~^^ HELP: duplicate serde attribute `serialize_with`
|
||||
x: (),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user