mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 21:48:02 +00:00
Compare commits
1583 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b92c80cc1 | |||
| c1c0ede452 | |||
| 4a66c5f33d | |||
| 714c8a5586 | |||
| dc0c0dcba1 | |||
| 54102ee7d0 | |||
| 14accf7518 | |||
| 55fdbea20b | |||
| 75d8902371 | |||
| 9451ea8df1 | |||
| c1ce03b3dd | |||
| a587eb8953 | |||
| 990f7eb6c1 | |||
| 082e18f9a1 | |||
| f309485787 | |||
| e2f85681fe | |||
| 8b840c3030 | |||
| 9c39115f82 | |||
| 89342af71e | |||
| 3c5e2d11f6 | |||
| 3805c037a8 | |||
| 7045fee260 | |||
| 9d81532e41 | |||
| 5e47432ef0 | |||
| e0fc46783d | |||
| ca772a14f9 | |||
| 7b840897a9 | |||
| 967795414b | |||
| 985725f820 | |||
| 0c303d85d7 | |||
| f68e9e901e | |||
| 1094e2d334 | |||
| d9c338ec4a | |||
| 699bf3a75d | |||
| dd29825217 | |||
| 6366f17da7 | |||
| 1120e5af4a | |||
| 1093f7e232 | |||
| 2ea132b8c4 | |||
| 2ebc771b88 | |||
| c17c4eef18 | |||
| 7aa4950504 | |||
| 47015a2727 | |||
| dc4c31eb50 | |||
| b53ebef438 | |||
| 6c3bf7a2fc | |||
| ce0844b9ec | |||
| e9270e59f0 | |||
| 72060b779a | |||
| 1bb23ad9d1 | |||
| 9be4c9654a | |||
| 4114e90bac | |||
| 8bb07b0743 | |||
| ba8c1d63c8 | |||
| 857a805993 | |||
| 5a8dcac2ed | |||
| 697b082e90 | |||
| d91075c8d5 | |||
| 4118cec731 | |||
| c261015325 | |||
| 6b5e5a83d0 | |||
| bc6b2b1dee | |||
| beb21cb640 | |||
| 7cfebbcd72 | |||
| b60c03ec3f | |||
| 3257851192 | |||
| 9a84622c56 | |||
| de8ac1c0be | |||
| 3d6c4149b1 | |||
| 29cdf888c0 | |||
| 2ba97394fb | |||
| 6699b0bc40 | |||
| b054ea4105 | |||
| e5efb6ad93 | |||
| 1f423580a5 | |||
| 033114a4ae | |||
| 7cec99c7fd | |||
| 6c5bf701be | |||
| 6e800ff826 | |||
| 68bda7a004 | |||
| dfeaf77bb2 | |||
| b0cc213e57 | |||
| 74ca06662e | |||
| 38edb473de | |||
| 1c03647656 | |||
| aeee73fe92 | |||
| 1a3ef39040 | |||
| deaf600af7 | |||
| 48556a4c7f | |||
| d88a4748f7 | |||
| ffed19243d | |||
| bb7f94df84 | |||
| ff0f467e25 | |||
| d1975f3661 | |||
| b91713e824 | |||
| 6ea446fb4b | |||
| 85c6904a93 | |||
| 2fd5212204 | |||
| 7d1bc1f0fc | |||
| cdc2fa1b9f | |||
| ac4001e590 | |||
| fbcb2230bb | |||
| 86c88bea12 | |||
| 82d0fe00fd | |||
| e61261e002 | |||
| 9fd56cd41c | |||
| e81f54fbc8 | |||
| c67017d466 | |||
| f6e7366b46 | |||
| 1f9f72bc48 | |||
| e24dbc418d | |||
| 18e5b03fd1 | |||
| 5aa163f27e | |||
| 3728d3c67a | |||
| 3f48ed36cc | |||
| b6a2d07f26 | |||
| 84ad76b2e5 | |||
| e6b6602a42 | |||
| 999b94d6ae | |||
| fa6712d2bf | |||
| 012ea8eb84 | |||
| 9add5812e2 | |||
| 5fd52100b6 | |||
| 6670a309ca | |||
| b7bad3a165 | |||
| 4e002ece07 | |||
| eaccae2c46 | |||
| 990a502c39 | |||
| 661206d885 | |||
| 51d4563ed1 | |||
| 7db0982e58 | |||
| ed04824f10 | |||
| 88ee470a1c | |||
| a5ecbdb4f4 | |||
| bd588db067 | |||
| 8f09aeacdd | |||
| 0b5c56b0db | |||
| 85de92e6f7 | |||
| c858a1fa77 | |||
| d02eb22557 | |||
| 034fe25d5b | |||
| 0a230e8598 | |||
| b20214d4a0 | |||
| 34f4b68f77 | |||
| 60e08f9545 | |||
| ba46f45dc5 | |||
| 44b9567e21 | |||
| b276849ce1 | |||
| 398fba9b1e | |||
| cd6697b0e4 | |||
| c162d51866 | |||
| 78a9dbc57e | |||
| 391d3ababf | |||
| 99d9151ce9 | |||
| 4c89cf89fd | |||
| b0c99ed761 | |||
| dd1f4b483e | |||
| 91bfa8f947 | |||
| 8847800ce2 | |||
| 3c9fa1ccdf | |||
| 3c29a8857f | |||
| a5da27e16d | |||
| e797431268 | |||
| 4a335f8933 | |||
| 84721920fd | |||
| 192c7819ee | |||
| ede40bdfaa | |||
| e3d871ff7b | |||
| 5cbc8439ea | |||
| 0e1c4093c8 | |||
| 0d5b6c180c | |||
| 97c350a95e | |||
| 920a77ad61 | |||
| a227a87865 | |||
| 7a7a182ab6 | |||
| 9e1f573f88 | |||
| 094f63b86a | |||
| 42fa79455e | |||
| 104ad9a7dd | |||
| 23c14e5f33 | |||
| e80571751d | |||
| 0737474640 | |||
| 34de1e00c8 | |||
| f6eb34a830 | |||
| 8084258a3e | |||
| fc3f104c4a | |||
| 4bec9ffd0f | |||
| e6d2322e68 | |||
| 2b504099e4 | |||
| db3074a40f | |||
| 2e821eab4b | |||
| be7d0e7eb2 | |||
| b539cb45d7 | |||
| a5490e20e1 | |||
| 45c45e87bf | |||
| 2e76f7013f | |||
| d35de19120 | |||
| e5b3507145 | |||
| 7ea7c2ceb9 | |||
| 2b5b15967e | |||
| 2ef60b62ac | |||
| e6f086d85e | |||
| bf76f50294 | |||
| ba07075590 | |||
| 26186bddd1 | |||
| 53b9871b17 | |||
| f8787c3ca8 | |||
| 3022064f84 | |||
| 9e140a2071 | |||
| 24e6acbfae | |||
| 29c5a50935 | |||
| c619b2a7c4 | |||
| 764ebd9b17 | |||
| 010444dfa4 | |||
| 9c6f0c3a0e | |||
| a9f8ea0a1e | |||
| 04faac962a | |||
| 7e5701ad2b | |||
| 1cd10a7d09 | |||
| d5e6436b28 | |||
| 8ff11dc234 | |||
| 6b3777b617 | |||
| 7350b58f5c | |||
| 7351e0e55a | |||
| b3ff7e43ef | |||
| a50e1c20e9 | |||
| 6980727d74 | |||
| bb1dedf04d | |||
| f3520e526b | |||
| e8fd2c85c3 | |||
| 97962d51e2 | |||
| 95b1a5d3d9 | |||
| 0856a2c101 | |||
| 9f331cc257 | |||
| ef16c815f6 | |||
| c45a809d5c | |||
| f7d06cae4c | |||
| 31fe82a215 | |||
| ef6ed1d1be | |||
| 9d1251548b | |||
| c20730ee39 | |||
| afd51ef0f4 | |||
| 3167f98689 | |||
| 078b171c1b | |||
| da8d6f678e | |||
| 548eb8f667 | |||
| 1fe39043ee | |||
| c2114491ca | |||
| 9f47c47cad | |||
| d6b39fd2c1 | |||
| 4d6d0ae539 | |||
| dda070f45c | |||
| b97a183e82 | |||
| 9433004307 | |||
| 9476838264 | |||
| 172edc4cf4 | |||
| 3c97e1b9a9 | |||
| a81968af3c | |||
| ea2789df0f | |||
| b7cfe33101 | |||
| 1b8ebf6b64 | |||
| 35ad468780 | |||
| 850a29beb1 | |||
| 16bf9871cd | |||
| 6182eceed1 | |||
| 99bc52f685 | |||
| 726ff5ed31 | |||
| f63acb52dc | |||
| 36a66873cc | |||
| 63809e69c7 | |||
| f44402e224 | |||
| 099fa25b86 | |||
| c120c4518b | |||
| 115c1b4830 | |||
| 23db3a41e7 | |||
| e2ff603587 | |||
| 19a11237b8 | |||
| 732544aed6 | |||
| 65dfa607c8 | |||
| 59104bbc24 | |||
| 38ad09aeb7 | |||
| 02631cef42 | |||
| f369707dc5 | |||
| e16e924c21 | |||
| 8b52ddd5b9 | |||
| 112f2040ea | |||
| cd836eb3ca | |||
| 2b4355724e | |||
| 5534bf4df1 | |||
| 60522937af | |||
| 29be721f79 | |||
| 0c4ffad9ec | |||
| 03addbae55 | |||
| 0bab6be124 | |||
| b6def5300a | |||
| 1b35c9e27e | |||
| d1564525ad | |||
| 645f672a55 | |||
| a135199ab1 | |||
| 2a9971a69d | |||
| e2ada0efef | |||
| 69653a762d | |||
| c33fb95127 | |||
| ec6ca6bf73 | |||
| 078e88b223 | |||
| 1894cb703f | |||
| 27c283ab53 | |||
| 142955b109 | |||
| a61cd0f236 | |||
| cb1632e957 | |||
| dbf1f9ab8f | |||
| 137ab48aff | |||
| fc43def8a3 | |||
| 2a351016ed | |||
| dfa321a1dd | |||
| 895eb2ba6c | |||
| cd365de70c | |||
| 7f799f3948 | |||
| 234fbfd7e3 | |||
| b9909cef3d | |||
| d540e72fc7 | |||
| 13d0899776 | |||
| 4fefa7a01d | |||
| 90486607a1 | |||
| 0b303c766c | |||
| c371563bfc | |||
| d17d8eb3ee | |||
| bcaebdb2b7 | |||
| 43a9f59c18 | |||
| ff70409215 | |||
| 97a98a7031 | |||
| 533fb9cc44 | |||
| 59b99d2d60 | |||
| c796daed7c | |||
| 6e2c385fa5 | |||
| 9a0e4e0176 | |||
| 640f8e0e82 | |||
| 4eb580790d | |||
| a2c83d754b | |||
| 6f946b20ec | |||
| 4dda90502a | |||
| dc6dbba47c | |||
| 2ceabad360 | |||
| a00aee1495 | |||
| 4e31c9984d | |||
| b8772a1e40 | |||
| 42990d8264 | |||
| cf31418555 | |||
| 5db72b8ad9 | |||
| fe8f8bcf7b | |||
| d4d737de8d | |||
| 52f6e96ee8 | |||
| 44fa7b0f6b | |||
| bda561df4e | |||
| 8955420baf | |||
| 21ee256911 | |||
| 4aba6fae78 | |||
| fe06bc2f88 | |||
| 8dfb4cd02f | |||
| d1ade37827 | |||
| 9de49241fb | |||
| b24d50160a | |||
| e46463e69f | |||
| a3157c9572 | |||
| 0d4722680a | |||
| 7ab12597bb | |||
| b86a46c83c | |||
| 187a0a3ec0 | |||
| 111c18dec3 | |||
| 7a2b137912 | |||
| 791b9fbe81 | |||
| 0fdc0257aa | |||
| b6a77c4413 | |||
| 33438850a6 | |||
| fcbb3d3783 | |||
| acc8640c1e | |||
| c083cfd65e | |||
| 4cea81f93f | |||
| 2d36be753a | |||
| 738d29eaa9 | |||
| b536fb67a4 | |||
| b10c23a950 | |||
| 85a5cf7cb1 | |||
| 192f5cd647 | |||
| 7dceee64fe | |||
| 8ad6ae71c6 | |||
| 3ea85a28cf | |||
| 273ecdb786 | |||
| de40eb7306 | |||
| b9c44073ce | |||
| d6e5947ad2 | |||
| 668651ee01 | |||
| fb1cacc10e | |||
| 735e56c26f | |||
| 97de3dccbb | |||
| 690467cbe2 | |||
| 71efd8ffda | |||
| 9bb196ae6e | |||
| ce75418e40 | |||
| 78c7f09e28 | |||
| e7269ac84e | |||
| 34866e20a8 | |||
| 3ae2bee272 | |||
| d0fb958e99 | |||
| b941c63a53 | |||
| cf70c3fb05 | |||
| f249e72162 | |||
| 92e0b62c6b | |||
| cf32a5b204 | |||
| 7b0e06c825 | |||
| 3158bf9093 | |||
| 01fade764c | |||
| 210c2419be | |||
| da05163d51 | |||
| f3e2bb5104 | |||
| 7a4c1086b5 | |||
| e89feb9635 | |||
| 5f72766c27 | |||
| 85ae57040d | |||
| d55a4a279f | |||
| bee9299693 | |||
| 9529fcec96 | |||
| bcec168e23 | |||
| 102a332616 | |||
| a280942f02 | |||
| 637dba5c2a | |||
| 24f292d081 | |||
| fa5c99e48a | |||
| 48f1a2c9b2 | |||
| 50ebbd63c6 | |||
| 4e5f63ff45 | |||
| de709e72a8 | |||
| 56d3c8f071 | |||
| ce89adecc1 | |||
| bc7a85063d | |||
| 0574f1e020 | |||
| f9fdd60e2e | |||
| 1c1eecabc0 | |||
| abd3fd004e | |||
| 15ee353488 | |||
| e75efbfd31 | |||
| 1c97a7ecb3 | |||
| fccd3e9fba | |||
| 4cb13b33e0 | |||
| 629802f2ab | |||
| afb1754528 | |||
| dbd67c6c89 | |||
| ed01bdb9dd | |||
| b54821d8ab | |||
| 89c6a79b6e | |||
| cd0412bddc | |||
| e42262f0f5 | |||
| 0a3eeab273 | |||
| e4e110e28f | |||
| 0726623389 | |||
| fd9d334d01 | |||
| 840eb14121 | |||
| 8fef196ee4 | |||
| 9c756f1ec0 | |||
| 4c29eea790 | |||
| 6dd2b4607f | |||
| 1e9ae88f53 | |||
| 5cc3902ab9 | |||
| c8e09e2d6d | |||
| e2a2ba116c | |||
| 0a9d24a218 | |||
| c222183669 | |||
| 140f9beee7 | |||
| 28ce892617 | |||
| 1e6d3ff99b | |||
| fba1b92cbf | |||
| ce1686379d | |||
| 79a20e9e33 | |||
| e9cd73f78e | |||
| 0be7f36d51 | |||
| 4c6cb6e359 | |||
| 82bde8d166 | |||
| 465392b618 | |||
| f3c6b9f05a | |||
| 2f1945eaf2 | |||
| b4d8a55b2a | |||
| 0e6ce8fa50 | |||
| a295c38ba3 | |||
| 295730ba1e | |||
| ac0d8f61c5 | |||
| b811588fa0 | |||
| 5fcdf0ff2b | |||
| 650b723da3 | |||
| 97920be33a | |||
| 58bbaa9e80 | |||
| 94f152730c | |||
| 535e3d4372 | |||
| 2ea43c8986 | |||
| 71fe2a5534 | |||
| f3ffcfd61e | |||
| bf27b28554 | |||
| 344602d27e | |||
| 64c483cf80 | |||
| 19091aacc7 | |||
| ef9028d798 | |||
| 1668cd19d3 | |||
| 134f268cee | |||
| c473633676 | |||
| 6a3a82007c | |||
| 1d6ef76cfb | |||
| c8e3959435 | |||
| 796f412a1e | |||
| fa854a2108 | |||
| 3a097ff2d2 | |||
| 8463bfc1e5 | |||
| 7a72b4c624 | |||
| 670c179417 | |||
| 1b1d868837 | |||
| d9704d02bb | |||
| 1349548367 | |||
| 18b1604fc8 | |||
| 0def7da5a8 | |||
| 4bb45c8252 | |||
| bb99b31eb0 | |||
| 84397183f3 | |||
| aeae265777 | |||
| a9c5df5da1 | |||
| 96576c4de9 | |||
| 9ec68e5829 | |||
| face857d5e | |||
| 85a1cc9b4f | |||
| 630501b93d | |||
| 8bbc2995ca | |||
| 7d3872df57 | |||
| 1ed228b92b | |||
| b605cd1bb9 | |||
| fea4e8e5b6 | |||
| 1df8b5785b | |||
| 981a75d7c9 | |||
| 11cc7014b3 | |||
| 0b667c88fa | |||
| 054ab1adaf | |||
| f1f8386f2e | |||
| ba8c3970b0 | |||
| 2f36b26a5c | |||
| 9b4edb3a1d | |||
| b8adc5ffa2 | |||
| bd90cafda7 | |||
| 6d43a08a1d | |||
| e71b8598ae | |||
| 95d0f437e3 | |||
| c95ee3968a | |||
| c22dd4ada5 | |||
| 727a40fc5a | |||
| ce84a5f1d3 | |||
| e6fda1c410 | |||
| 294dccc5be | |||
| da346a8878 | |||
| c5ccb995ad | |||
| 05ab569a80 | |||
| ab3f4971f0 | |||
| 47e238aa13 | |||
| e49b6c708b | |||
| eb7250792b | |||
| 7e5066b878 | |||
| 889e17816f | |||
| b1b9702daf | |||
| 32728d2f1d | |||
| 807a097387 | |||
| 794ee15386 | |||
| 2359417804 | |||
| 7950f3cdc5 | |||
| b87f8f35ee | |||
| 9e53405f43 | |||
| c6c1d8fa86 | |||
| 8aa5c2b45d | |||
| 414fd694c0 | |||
| 7e82809592 | |||
| 0dae5db30e | |||
| 5c24f0f0f3 | |||
| c2591e9b39 | |||
| 8ce0dee6da | |||
| 16daba8ea9 | |||
| 8b4074ee77 | |||
| 85fbd8793a | |||
| 65705e2091 | |||
| 385a385c62 | |||
| 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 | |||
| 8d113e67d6 | |||
| 6e206ce053 | |||
| 47fc9af472 | |||
| 1651f86d56 | |||
| 1157ac0118 | |||
| 202c10147e | |||
| 9f38ca032e | |||
| 00178ba795 | |||
| 24700ebeb6 | |||
| f06001c086 | |||
| ec773fb7db | |||
| da8b457f66 | |||
| a6e94e7122 | |||
| 629bf7b354 | |||
| 4415d10c61 | |||
| def8d6e8af | |||
| 2e824e9aba | |||
| fd14332729 | |||
| c413775574 | |||
| 5efb22ebee | |||
| 3e535325e1 | |||
| 5653e5b15c | |||
| 8d85860064 | |||
| eed18ffab2 | |||
| f8e1fa8ebc | |||
| 860241aa88 | |||
| 6f6c60867d | |||
| 77376f39ea | |||
| 302fac91a3 | |||
| 9c659d9d86 | |||
| 21698f264a | |||
| ba002e1119 | |||
| 8b44eb8bfc | |||
| d82a0cc5ff | |||
| 801fd1dc19 | |||
| 222779d46c | |||
| b1c1d964e1 | |||
| b77cfb635d | |||
| c42c08a25b | |||
| 48997cbb5b | |||
| d8ccd8809e | |||
| d2b65e0a5d | |||
| 7c04c98e0e | |||
| a2fa4c2570 | |||
| 42430902e2 | |||
| 23e2e92237 | |||
| 273b2c11c6 | |||
| c1602a4d76 | |||
| c23be3f855 | |||
| 5c9c97c0ce | |||
| e5ed440136 | |||
| d45ca2f5e4 | |||
| d7f9f8209d | |||
| 4a2612ecff | |||
| 05b22a06d7 | |||
| 3145bcc46e | |||
| 2b18b57d84 | |||
| 5520202262 | |||
| 3d647f4063 | |||
| 0fde3c2ee8 | |||
| 27f935f036 | |||
| 99614c7266 | |||
| bb2ecb3bc4 | |||
| 96393bfcc7 | |||
| 1d92569abc | |||
| e4ef087735 | |||
| 695c3eedcb | |||
| 50c636a923 | |||
| 5b884b5bf9 | |||
| 8637dda60f | |||
| abeea89147 | |||
| 6e324e887d | |||
| 7c596c7136 | |||
| f02dbf381b | |||
| 7cf184624a | |||
| c5a3128492 | |||
| 205f606962 | |||
| ad40f976db | |||
| 58d52e784b | |||
| d44f12907b | |||
| 61b167be9a | |||
| f1af2dc5ab | |||
| ebc61baab2 | |||
| ffcde25b6e | |||
| 2f57cecf13 | |||
| bfdcbae9db | |||
| ca41e16e92 | |||
| 352fe7b451 | |||
| 49e302d17d | |||
| b8602a7e43 | |||
| a8c8c2028e | |||
| d1833c5602 | |||
| b4ef7ac323 | |||
| ebf80ac965 | |||
| 112dfd7428 | |||
| b692923321 | |||
| 9e8cda4c37 | |||
| 5457394f5b | |||
| 6627540dd6 | |||
| 5ae06bba49 | |||
| 571bb8caed | |||
| 299cd2dbd0 | |||
| 583c0d8d14 | |||
| 07d07347b3 | |||
| 77b07f3fbf | |||
| 1bd2c6129c | |||
| 39413c8ce7 | |||
| b4dbae250b | |||
| 5a91ac5ba5 | |||
| 7ad836e6a9 | |||
| 72ecb9064c | |||
| 23c6eb3b40 | |||
| b8c9a66d75 | |||
| 56b2e39dda | |||
| 5bc805329e | |||
| 69dd3215f4 | |||
| a7a7a31809 | |||
| af9996aa9a | |||
| 0d4d47c398 | |||
| 30361ac6d0 | |||
| 3f75239bfb | |||
| 8dd5605a40 | |||
| f288a41768 | |||
| f4b78e202a | |||
| 0ddebe0317 | |||
| 9fc526b788 | |||
| a799ea171c | |||
| d6f07f2f47 | |||
| f9946ee0ca | |||
| a164f52315 | |||
| 8bba8447ef | |||
| 9db784bccd | |||
| 9317bc5afa | |||
| a185df1e77 | |||
| 1bdf5ecec4 | |||
| 59017aa19b | |||
| 6b4625dcbb | |||
| 6e01f220b1 | |||
| 64573319f9 | |||
| 3d64df6e87 | |||
| cc2558b0dc | |||
| 5c41661bce | |||
| dd6914a203 | |||
| 63623eb3b3 | |||
| ddc4b50d4d | |||
| b313f947dc | |||
| 16bc9fb99e | |||
| 34eaab00f7 | |||
| 6024e717fb | |||
| ef4dd6c0ec | |||
| f7ed967db1 | |||
| 613e46b0ee | |||
| b2d2e96267 | |||
| ae0373643c | |||
| 7aeabddd2f | |||
| 9df8f5ecc0 | |||
| c4fad2883b | |||
| 9cfcd78c87 | |||
| 4751627f1c | |||
| ae59c6b6d2 | |||
| 4973d7a62d | |||
| ed6a1de311 | |||
| ab234be025 | |||
| ee75e6c0e9 | |||
| c2b390fe63 | |||
| 56d5d7f761 | |||
| 0b89bc920e | |||
| 0dac13e4db | |||
| 0c2e91f28a | |||
| 13e7bee0e6 | |||
| 65104aca9c | |||
| 9360094ba7 | |||
| 3700779bfa | |||
| d9e894911f | |||
| 85e3ddc2b8 | |||
| ccae35d92a | |||
| 61ca928325 | |||
| a93f2ebff0 | |||
| a45f1ae915 | |||
| 9641978481 | |||
| ffd2017c6f | |||
| b7eb42aa6b | |||
| 750f8ba299 | |||
| 49cdef074d | |||
| aa86b04714 | |||
| c887a0b472 | |||
| 34936be574 | |||
| e354dd0c7f | |||
| bc221abb04 | |||
| ab5e8780ab | |||
| 0c34e06e51 | |||
| 4a0c4e0c25 | |||
| 8c34e0940f | |||
| eb6bf16a51 | |||
| 797d049db5 | |||
| d61a373f12 | |||
| e0eea551b4 | |||
| c650a92bf7 | |||
| f218f4d7bf | |||
| 8c0a2015be | |||
| 4773863e3a | |||
| 80cd9c7617 | |||
| 436cafb0a3 | |||
| 98bb02e9b4 | |||
| 142439088c | |||
| ce81288235 | |||
| 88d5fe6bfd | |||
| 9a2c352025 | |||
| 61c90cb8cb | |||
| 66e8b0a0cd | |||
| 9e7a3437d9 | |||
| 7ac8d4f9ae | |||
| 501bae42f5 | |||
| 7a0397451e | |||
| 16787318d1 | |||
| f4ae0888c8 | |||
| 213071fe5c | |||
| cfd26c6fda | |||
| 23fa83941e | |||
| 88f5b9511d | |||
| d537f1e1f0 | |||
| f6ac232580 | |||
| aad7a7987f | |||
| b24ad76880 | |||
| 5796f1a0f5 | |||
| 6437167930 | |||
| f98daaa250 | |||
| b8a40551a2 | |||
| 40db31691a | |||
| ab68132b1f | |||
| e70bbd9dde | |||
| d5e5c520ac | |||
| 1b9a096fa7 | |||
| 39e05ffad2 | |||
| 78fab25c5c | |||
| 2a557a1e36 | |||
| ab0848f780 | |||
| 2b1303f59c | |||
| 7f9ba155cb | |||
| a4e0c2f055 | |||
| 3bbf70575b | |||
| ad680cbd44 | |||
| ff0cfb1f1f | |||
| 9b08915a18 | |||
| 501aa3ee1d | |||
| eebf0f8db8 | |||
| a7e4911ddb | |||
| eb08f037f5 | |||
| aa03fd5d1a | |||
| e198afb0c1 | |||
| bc8de251cf | |||
| 99e8686189 | |||
| 826f656e28 | |||
| ab7c003b64 | |||
| 422191fcb0 | |||
| 4ba748c902 | |||
| 14ed6f2dab | |||
| 30606a43aa | |||
| 9be3d32016 | |||
| 5daf1b89a1 | |||
| f8f5d0ca2f | |||
| 57873cce28 | |||
| 4ed0362c8e | |||
| 4cecaf8d02 | |||
| 50c696aabe | |||
| 2f58a20bc6 | |||
| 030459a040 | |||
| e9b530a000 | |||
| ea1a729088 | |||
| 857dcea774 | |||
| b98a9a8f9b | |||
| 3b135431fd | |||
| 945d12c0b4 | |||
| e36915300f | |||
| 85c05d301a | |||
| c2474bf6ee | |||
| a52f436788 | |||
| ad3335e5d6 | |||
| 4b00de0e22 | |||
| 8403fa018e | |||
| 0e9f1b42de | |||
| 0085d05e55 | |||
| 2eed855bff | |||
| c3eced410f | |||
| 8a630fea7c | |||
| 2e597ed3f0 | |||
| 0963121beb | |||
| 15b2714058 | |||
| 9ce107de25 | |||
| e47284c0e0 | |||
| 800620e2aa | |||
| 40c670e625 | |||
| ba260b0e5f | |||
| 8452e313cc | |||
| 0dccbb1f11 | |||
| deca49315a | |||
| 95407a4ca5 | |||
| 2fe9a860cd | |||
| e67d941b78 | |||
| d4042872f5 | |||
| 64af86b830 | |||
| 370c8a91cb | |||
| 972da59ebc | |||
| a42008f695 | |||
| e4ea2a56e9 | |||
| 7650a48fdd | |||
| d665a2f2b2 | |||
| 44e23254c9 | |||
| 552971196d | |||
| 0681cd5003 | |||
| d965367238 | |||
| a6df35b3d2 | |||
| 9fc180e62f | |||
| 5b815b7001 | |||
| 4831482695 | |||
| d3e5dd9cd7 | |||
| 26098ed877 | |||
| 42ed62cf24 | |||
| 9f0973aff7 | |||
| ccec002bf3 | |||
| f36a1e0895 | |||
| e6487cf6fa | |||
| 4f2e8d5dbb | |||
| 1c2a4bff1c | |||
| 85bccf42b6 | |||
| 959fee024f | |||
| 8ede8c8e2a | |||
| 83537c95e1 | |||
| fa9057fa31 | |||
| 0084d82a50 | |||
| b504b08782 | |||
| 775e8154e7 | |||
| 9c679d9082 | |||
| b0f9d2a0ba | |||
| f39b1db96a | |||
| 9ecb0839de | |||
| 8a4c116812 | |||
| 1d3e921ba6 | |||
| 8e8694261b | |||
| 4fdba725fe | |||
| 75eed8cdde | |||
| 6801a13650 | |||
| 25ab84d4b9 | |||
| e43d3f3e4f | |||
| b37d47c987 | |||
| eec7101894 | |||
| 5dd327fb02 | |||
| fd3d1396d3 | |||
| c47b4c8e0b | |||
| 2d793b82f6 | |||
| 237be46e29 | |||
| 3d7aad1e7b | |||
| e792874369 | |||
| 1669c69714 | |||
| 4d5e450054 | |||
| 26b22e647d | |||
| cda1fc46b0 | |||
| c68b959696 | |||
| eab80172e4 | |||
| c1259fbc87 | |||
| 58e30eaee4 | |||
| bafa941004 | |||
| f347b2d363 | |||
| 3f9fc49cca | |||
| c913527944 | |||
| 8fafc7420c | |||
| bea1c5b0f5 | |||
| aa37caf216 | |||
| 2440b59aae | |||
| 873cfbe9ab | |||
| c96efcb87a | |||
| b53026a21b | |||
| c7901e532e | |||
| 2af0701be6 | |||
| ae79451b7a | |||
| b220f264a5 | |||
| 1a2b3815ef | |||
| 6fbf40b83c | |||
| 1d6ecf3c2c | |||
| d7ccef0cac | |||
| 2d465415c5 | |||
| bc2d637112 | |||
| cf1cdadc77 | |||
| 4a9cb3395d | |||
| dfa6623a24 | |||
| a8adac6b93 | |||
| b9b7922ef1 | |||
| a369ee156f | |||
| d1253cb193 | |||
| bc982f9757 | |||
| 0240814677 | |||
| 670be2ce2f | |||
| c893e3e872 | |||
| fe8141fd70 | |||
| aa750d2bf3 | |||
| 4cea214da2 | |||
| 15341780a2 | |||
| 4767ca3f5d | |||
| 26a6ba177c | |||
| 974c8434e9 | |||
| 0734b44a3a | |||
| d0f846182b | |||
| 7a7d4c6364 | |||
| c567e749ef | |||
| b8a6e68322 | |||
| 6279b0d930 | |||
| a778425d0f | |||
| faaf5ee115 | |||
| 86deb8db79 | |||
| d4d2061a2e | |||
| c202ce13dc | |||
| 1c9478bfa6 | |||
| 739ad64c7c | |||
| 3eef7c87c9 | |||
| e0c040a3a2 | |||
| c13a37d4db | |||
| 4354aab93a | |||
| 691e304fff | |||
| 13463e25c2 | |||
| 54bbf81dfc | |||
| cdfd445528 | |||
| 30e8c84d01 | |||
| a35bde49c6 | |||
| f9535a4d67 | |||
| 6d55501dab | |||
| 5b118fdef4 | |||
| 337c6e91d8 | |||
| b0dc7ea6da | |||
| 67d56ae427 | |||
| 6829c10a10 | |||
| 6a37472023 | |||
| d10fa2bd86 | |||
| e722cf8791 | |||
| bc4205a1d0 | |||
| ea5af417fb | |||
| c70c364754 | |||
| 9cda4563c0 | |||
| fc927e0e25 | |||
| 7915835a93 | |||
| 0c5db90de8 | |||
| 637332de2d | |||
| e77e7c4bba | |||
| 1798d1af6e | |||
| 31cec05712 | |||
| f2de0509f5 | |||
| 26d357e846 | |||
| 4e2f08cc7a | |||
| 91a0f248a1 | |||
| 03462b6e39 | |||
| 37f8ea234f | |||
| 3f920f645c | |||
| a937a06d3e | |||
| dd092dce95 | |||
| dfea7ec939 | |||
| 0e7c027ff1 | |||
| 8b6f77095a | |||
| dbe7d04282 | |||
| fb7964fde7 | |||
| f45b83f0c1 | |||
| f28abe8fde | |||
| 15faaf8bc3 | |||
| a15636f808 | |||
| 5d396c4e3b | |||
| bdccde5c9b | |||
| 7dd01dd54a | |||
| e4b21e6caa | |||
| 2afbffa924 | |||
| 385f83a7de | |||
| 50f5ef2fb6 | |||
| 13f273ad74 | |||
| 09bd8287e7 | |||
| 35313257c5 | |||
| 07bce54ad3 | |||
| 41488252ff | |||
| 8d1f882512 | |||
| dec6b67236 | |||
| 0cf8eadef8 | |||
| 7d16710fb4 | |||
| 9253fccf04 | |||
| eab771cd1a | |||
| 4f6518dad7 | |||
| f8e53e837d | |||
| c5854f19f7 | |||
| 5bb6de80b2 | |||
| c4e31bd968 | |||
| 2887c379de | |||
| ea8fb97beb | |||
| c5bd760133 | |||
| 942642c0f4 | |||
| 78407e19a9 | |||
| 47a4e61b8b | |||
| 5141270346 | |||
| dc7ab2696a | |||
| 14034968df | |||
| aef136934b | |||
| 7d0a38270d | |||
| 07154303ed | |||
| 4f39766211 | |||
| 304b598a05 | |||
| afd080d005 | |||
| 1232cfd194 | |||
| 7e72d8bf66 | |||
| 0d82bbf74f | |||
| aed5a77540 | |||
| f54d597b2e | |||
| 2efb95015b | |||
| f88db0f547 | |||
| 0b7accf86c | |||
| ab82f09e5d | |||
| 0f72d1a388 | |||
| ef3489a23e | |||
| 8bbab627a0 | |||
| 76ff216a5f | |||
| b40ecf04ce | |||
| eeaa095cd3 | |||
| 1985cfc955 | |||
| 517270a943 | |||
| 6a6606cd64 | |||
| 174867295b | |||
| ad5bf04c4e | |||
| 2deacf8eaa | |||
| e133b8b708 | |||
| 52e93150e6 | |||
| a38b24136b | |||
| 78f682590a | |||
| 528ec3cdd8 | |||
| 1986c17052 | |||
| 5ec317a899 | |||
| 9d8987bde8 | |||
| a6d172111b | |||
| 9271f7c48c | |||
| 74e15ea9f5 | |||
| 2c49f9aad3 | |||
| cc933b9cdb | |||
| fdaa8202b9 | |||
| 85d4dc3e20 | |||
| 11a6e42256 | |||
| b1cfa5aef5 | |||
| f2b230a0b8 | |||
| 8aa630ea48 | |||
| ad249c7fac | |||
| fccb395168 | |||
| 8d130123d9 | |||
| d97c4f403c | |||
| e86e716f7a | |||
| 870305aa93 | |||
| b9be543596 | |||
| 43d49f54be | |||
| 753c711cd7 | |||
| 2e9cc6e98a | |||
| 726eea9a97 | |||
| 467b5fc595 | |||
| 995f2b3f76 | |||
| e57ce37ac1 | |||
| a581c0d147 | |||
| 21c2119349 | |||
| f12a951f22 | |||
| d2d4892873 | |||
| 2b449683f3 | |||
| 9d73271db2 | |||
| 7ef80a845d | |||
| 33760e122c | |||
| dd62801b22 | |||
| 5415abf80b | |||
| 6388019ad4 | |||
| 2fe67d3d72 | |||
| 1e32329e61 | |||
| e2a1f08e43 | |||
| 11c89695a1 | |||
| 5f49eb8b24 | |||
| 3cc14c2a6d | |||
| aa30ef827c | |||
| ebe214e8ac | |||
| 8fd41d3b28 | |||
| a7f6ad137a | |||
| 1b763da529 | |||
| b7d6c5d9f7 | |||
| e7d3d515df | |||
| 145733ce77 | |||
| 1a63cbccb2 | |||
| 07ac9eb538 | |||
| 14aa89aac8 | |||
| e66033e53e | |||
| dcb837b531 | |||
| 51d3fb1ebc | |||
| 826b53f691 | |||
| b6605b57e0 | |||
| f03e8e6056 | |||
| a33a9a5b26 | |||
| 67ed7a0edd | |||
| 9b51be4ba6 | |||
| c3d9b42cdf | |||
| b2377d4c0b | |||
| dee58ead7f | |||
| 887985523e | |||
| cabc299447 | |||
| 21adee8f40 | |||
| afaab12b66 | |||
| 93860d0643 | |||
| b43554fbb1 | |||
| 5871fb9ce0 | |||
| f05368ed24 | |||
| 732b91e53d | |||
| d03ecda333 | |||
| 7a722d5060 | |||
| 2795f0ed9d | |||
| 92bc23e484 | |||
| 5a98bd9ee3 | |||
| bfabaf3789 | |||
| cf6c4ab7ec | |||
| 7c27e10226 | |||
| 20ff9ba89b | |||
| 211e2bb8d9 | |||
| cee3efbda8 | |||
| fb48111e46 | |||
| 8c3e72f2c8 | |||
| aa46318425 | |||
| 3d3118f8b0 | |||
| b6f1a2eb55 | |||
| 8eb50186e0 | |||
| 4dec5f4de8 | |||
| 8e0c036158 | |||
| 7d985ff3fd | |||
| d3a2f5e268 | |||
| 59b3961ad4 | |||
| dbc9a60c5f | |||
| ce687431f3 | |||
| 71ccc5753b | |||
| 13886435a6 | |||
| 08e2182042 | |||
| d60595cc27 | |||
| 8c7396c35a | |||
| 42b2fd8eec | |||
| bc946e4fd7 | |||
| c488cec641 | |||
| fcc3c69a49 | |||
| 350c2e835b | |||
| a0a031677e | |||
| cc0d045f5c | |||
| aebe1fddab | |||
| 77ee306b57 | |||
| 6750fdaae1 | |||
| dd6989d551 | |||
| 0c2fed49e2 | |||
| a4ee9bd045 | |||
| 6d9397d573 | |||
| dc9445f873 | |||
| 17bc40ec1c | |||
| 2184fef82f | |||
| 7e1b5c6ce4 | |||
| 36da8a5cee | |||
| fbe85f399d | |||
| 880b27b19e | |||
| cc06f070d1 | |||
| 2f988aa5e6 | |||
| d294a10e83 | |||
| defcbef7ab | |||
| d90eecd4a2 | |||
| 0d6d077e6a | |||
| be09fc9bbb | |||
| fc9d78e26b | |||
| 9f83164c40 | |||
| 857974ab8a | |||
| d70636f4d4 | |||
| 09e467cc4c | |||
| a9a05350a9 |
@@ -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 ${{matrix.rust}}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [stable, beta]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{matrix.rust}}
|
||||
- run: cd serde && cargo build --features rc
|
||||
- run: cd serde && cargo build --no-default-features
|
||||
- run: cd serde_test && cargo build
|
||||
- run: cd serde_test && cargo test --features serde/derive,serde/rc
|
||||
|
||||
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 && cargo check --no-default-features
|
||||
- run: cd serde && cargo check
|
||||
- run: cd serde_derive && cargo check
|
||||
|
||||
alloc:
|
||||
name: Rust 1.36.0
|
||||
runs-on: ubuntu-latest
|
||||
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_derive_internals && 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
|
||||
+3
-2
@@ -1,3 +1,4 @@
|
||||
Cargo.lock
|
||||
target
|
||||
target/
|
||||
**/*.rs.bk
|
||||
*.sw[po]
|
||||
Cargo.lock
|
||||
|
||||
-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
|
||||
+41
-31
@@ -1,45 +1,55 @@
|
||||
# Contributing to Serde
|
||||
|
||||
Serde welcomes contribution from everyone. Here are the guidelines if you are
|
||||
thinking of helping us:
|
||||
Serde welcomes contribution from everyone in the form of suggestions, bug
|
||||
reports, pull requests, and feedback. This document gives some guidance if you
|
||||
are thinking of helping us.
|
||||
|
||||
## Contributions
|
||||
## Submitting bug reports and feature requests
|
||||
|
||||
Contributions to Serde or its dependencies should be made in the form of GitHub
|
||||
pull requests. Each pull request will be reviewed by a core contributor
|
||||
(someone with permission to land patches) and either landed in the main tree or
|
||||
given feedback for changes that would be required. All contributions should
|
||||
follow this format, even those from core contributors.
|
||||
Serde development is spread across lots of repositories, but this serde-rs/serde
|
||||
repository is always a safe choice for opening any issues related to Serde.
|
||||
|
||||
Should you wish to work on an issue, please claim it first by commenting on
|
||||
the GitHub issue that you want to work on it. This is to prevent duplicated
|
||||
efforts from contributors on the same issue.
|
||||
When reporting a bug or asking for help, please include enough details so that
|
||||
the people helping you can reproduce the behavior you are seeing. For some tips
|
||||
on how to approach this, read about how to produce a [Minimal, Complete, and
|
||||
Verifiable example].
|
||||
|
||||
## Pull Request Checklist
|
||||
[Minimal, Complete, and Verifiable example]: https://stackoverflow.com/help/mcve
|
||||
|
||||
- Branch from the master branch and, if needed, rebase to the current master
|
||||
branch before submitting your pull request. If it doesn't merge cleanly with
|
||||
master you may be asked to rebase your changes.
|
||||
When making a feature request, please make it clear what problem you intend to
|
||||
solve with the feature, any ideas for how Serde could support solving that
|
||||
problem, any possible alternatives, and any disadvantages.
|
||||
|
||||
- Commits should be as small as possible, while ensuring that each commit is
|
||||
correct independently (i.e., each commit should compile and pass tests).
|
||||
## Running the test suite
|
||||
|
||||
- If your patch is not getting reviewed or you need a specific person to review
|
||||
it, you can @-reply a reviewer asking for a review in the pull request or a
|
||||
comment, or you can ask for a review in `#serde` on `irc.mozilla.org`.
|
||||
We encourage you to check that the test suite passes locally before submitting a
|
||||
pull request with your changes. If anything does not pass, typically it will be
|
||||
easier to iterate and fix it locally than waiting for the CI servers to run
|
||||
tests for you.
|
||||
|
||||
- Add tests relevant to the fixed bug or new feature.
|
||||
##### In the [`serde`] directory
|
||||
|
||||
```sh
|
||||
# Test all the example code in Serde documentation
|
||||
cargo test --features derive
|
||||
```
|
||||
|
||||
##### In the [`test_suite`] directory
|
||||
|
||||
```sh
|
||||
# Run the full test suite, including tests of unstable functionality
|
||||
cargo +nightly test --features unstable
|
||||
```
|
||||
|
||||
Note that this test suite currently only supports running on a nightly compiler.
|
||||
|
||||
[`serde`]: https://github.com/serde-rs/serde/tree/master/serde
|
||||
[`test_suite`]: https://github.com/serde-rs/serde/tree/master/test_suite
|
||||
|
||||
## Conduct
|
||||
|
||||
In all Serde-related forums, we follow the [Rust Code of
|
||||
Conduct](https://www.rust-lang.org/conduct.html). For escalation or moderation
|
||||
issues, please contact Erick (erick.tryzelaar@gmail.com) instead of the Rust
|
||||
moderation team.
|
||||
In all Serde-related forums, we follow the [Rust Code of Conduct]. For
|
||||
escalation or moderation issues please contact Erick (erick.tryzelaar@gmail.com)
|
||||
instead of the Rust moderation team.
|
||||
|
||||
## Communication
|
||||
|
||||
Beyond opening tickets on the
|
||||
[serde-rs/serde](https://github.com/serde-rs/serde) project, Serde contributors
|
||||
frequent the `#serde` channel on
|
||||
[`irc.mozilla.org`](https://wiki.mozilla.org/IRC).
|
||||
[Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"serde",
|
||||
"serde_codegen_internals",
|
||||
"serde_derive",
|
||||
"serde_derive_internals",
|
||||
"serde_test",
|
||||
"test_suite",
|
||||
"test_suite/no_std",
|
||||
]
|
||||
|
||||
@@ -1,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,4 +1,13 @@
|
||||
# Serde   [](https://travis-ci.org/serde-rs/serde) [](https://crates.io/crates/serde)
|
||||
# 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://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
|
||||
[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.**
|
||||
|
||||
@@ -8,18 +17,38 @@ 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)
|
||||
|
||||
## Serde in action
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
<details>
|
||||
<summary>
|
||||
Click to show Cargo.toml.
|
||||
<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a>
|
||||
</summary>
|
||||
|
||||
extern crate serde_json;
|
||||
```toml
|
||||
[dependencies]
|
||||
|
||||
# The core APIs, including the Serialize and Deserialize traits. Always
|
||||
# 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.
|
||||
serde_json = "1.0"
|
||||
```
|
||||
|
||||
</details>
|
||||
<p></p>
|
||||
|
||||
```rust
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct Point {
|
||||
@@ -46,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>
|
||||
|
||||
@@ -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
|
||||
+38
-17
@@ -1,34 +1,55 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "0.9.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
version = "1.0.129" # remember to update html_root_url and serde_derive dependency
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
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"]
|
||||
readme = "crates-io.md"
|
||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
build = "build.rs"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
[dependencies]
|
||||
serde_derive = { version = "=1.0.129", 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"]
|
||||
|
||||
# Provide derive(Serialize, Deserialize) macros.
|
||||
derive = ["serde_derive"]
|
||||
|
||||
# Provide impls for common standard library types like Vec<T> and HashMap<K, V>.
|
||||
# Requires a dependency on the Rust standard library.
|
||||
std = []
|
||||
|
||||
# Provide impls for types that require unstable functionality. For tracking and
|
||||
# discussion of unstable functionality please refer to this issue:
|
||||
#
|
||||
# https://github.com/serde-rs/serde/issues/812
|
||||
unstable = []
|
||||
alloc = ["unstable"]
|
||||
collections = ["alloc"]
|
||||
unstable-testing = ["unstable", "std"]
|
||||
|
||||
# to get serde_derive picked up by play.integer32.com
|
||||
playground = ["serde_derive"]
|
||||
# Provide impls for types in the Rust core allocation and collections library
|
||||
# including String, Box<T>, Vec<T>, and Cow<T>. This is a subset of std but may
|
||||
# be enabled without depending on all of std.
|
||||
alloc = []
|
||||
|
||||
[dependencies]
|
||||
serde_derive = { version = "0.9", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = "0.9"
|
||||
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
|
||||
# does not preserve identity and may result in multiple copies of the same data.
|
||||
# Be sure that this is what you want before enabling this feature.
|
||||
rc = []
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
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 before Rust 1.40 since
|
||||
// Emscripten did not support 128-bit integers until Rust 1.40
|
||||
// (https://github.com/rust-lang/rust/pull/65251)
|
||||
if minor >= 26 && (!emscripten || minor >= 40) {
|
||||
println!("cargo:rustc-cfg=integer128");
|
||||
}
|
||||
|
||||
// Inclusive ranges methods stabilized in Rust 1.27:
|
||||
// https://github.com/rust-lang/rust/pull/50758
|
||||
// Also Iterator::try_for_each:
|
||||
// https://blog.rust-lang.org/2018/06/21/Rust-1.27.html#library-stabilizations
|
||||
if minor >= 27 {
|
||||
println!("cargo:rustc-cfg=range_inclusive");
|
||||
println!("cargo:rustc-cfg=iterator_try_fold");
|
||||
}
|
||||
|
||||
// Non-zero integers stabilized in Rust 1.28:
|
||||
// https://blog.rust-lang.org/2018/08/02/Rust-1.28.html#library-stabilizations
|
||||
if minor >= 28 {
|
||||
println!("cargo:rustc-cfg=num_nonzero");
|
||||
}
|
||||
|
||||
// Current minimum supported version of serde_derive crate is Rust 1.31.
|
||||
if minor >= 31 {
|
||||
println!("cargo:rustc-cfg=serde_derive");
|
||||
}
|
||||
|
||||
// TryFrom, Atomic types, non-zero signed integers, and SystemTime::checked_add
|
||||
// stabilized in Rust 1.34:
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#tryfrom-and-tryinto
|
||||
// https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html#library-stabilizations
|
||||
if minor >= 34 {
|
||||
println!("cargo:rustc-cfg=core_try_from");
|
||||
println!("cargo:rustc-cfg=num_nonzero_signed");
|
||||
println!("cargo:rustc-cfg=systemtime_checked_add");
|
||||
|
||||
// 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,315 +0,0 @@
|
||||
//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
|
||||
//!
|
||||
//! Without specialization, Rust forces us to treat `&[u8]` just like any other
|
||||
//! slice and `Vec<u8>` just like any other vector. In reality this particular
|
||||
//! slice and vector can often be serialized and deserialized in a more
|
||||
//! efficient, compact representation in many formats.
|
||||
//!
|
||||
//! When working with such a format, you can opt into specialized handling of
|
||||
//! `&[u8]` by wrapping it in `bytes::Bytes` and `Vec<u8>` by wrapping it in
|
||||
//! `bytes::ByteBuf`.
|
||||
//!
|
||||
//! Rust support for specialization is being tracked in
|
||||
//! [rust-lang/rust#31844][specialization]. Once it lands in the stable compiler
|
||||
//! we will be deprecating these wrapper types in favor of optimizing `&[u8]`
|
||||
//! and `Vec<u8>` out of the box.
|
||||
//!
|
||||
//! [specialization]: https://github.com/rust-lang/rust/issues/31844
|
||||
|
||||
use core::{ops, fmt, char, iter, slice};
|
||||
use core::fmt::Write;
|
||||
|
||||
use ser;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub use self::bytebuf::ByteBuf;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
#[doc(hidden)] // does anybody need this?
|
||||
pub use self::bytebuf::ByteBufVisitor;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::Vec;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Wraps a `&[u8]` in order to serialize in an efficient way. Does not support
|
||||
/// deserialization.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde_derive;
|
||||
/// # extern crate serde;
|
||||
/// # use std::net::IpAddr;
|
||||
/// #
|
||||
/// use serde::bytes::Bytes;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// #[derive(Serialize)]
|
||||
/// struct Packet<'a> {
|
||||
/// destination: IpAddr,
|
||||
/// payload: Bytes<'a>,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Bytes<'a> {
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Bytes<'a> {
|
||||
/// Wrap an existing `&[u8]`.
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Bytes { bytes: bytes }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str("b\""));
|
||||
for c in escape_bytestring(self.bytes) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for Bytes<'a> {
|
||||
fn from(bytes: &'a [u8]) -> Self {
|
||||
Bytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
impl<'a> From<&'a Vec<u8>> for Bytes<'a> {
|
||||
fn from(bytes: &'a Vec<u8>) -> Self {
|
||||
Bytes::new(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<&'a [u8]> for Bytes<'a> {
|
||||
fn into(self) -> &'a [u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Deref for Bytes<'a> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ser::Serialize for Bytes<'a> {
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
mod bytebuf {
|
||||
use core::cmp;
|
||||
use core::ops;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
|
||||
use ser;
|
||||
use de;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::{String, Vec};
|
||||
|
||||
/// Wraps a `Vec<u8>` in order to serialize and deserialize in an efficient
|
||||
/// way.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde_derive;
|
||||
/// # extern crate serde;
|
||||
/// # use std::net::IpAddr;
|
||||
/// #
|
||||
/// use serde::bytes::ByteBuf;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct Packet {
|
||||
/// destination: IpAddr,
|
||||
/// payload: ByteBuf,
|
||||
/// }
|
||||
/// #
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ByteBuf {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteBuf {
|
||||
/// Construct a new, empty `ByteBuf`.
|
||||
pub fn new() -> Self {
|
||||
ByteBuf::from(Vec::new())
|
||||
}
|
||||
|
||||
/// Construct a new, empty `ByteBuf` with the specified capacity.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
ByteBuf::from(Vec::with_capacity(cap))
|
||||
}
|
||||
|
||||
/// Wrap existing bytes in a `ByteBuf`.
|
||||
pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
|
||||
ByteBuf { bytes: bytes.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ByteBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(f.write_str("b\""));
|
||||
for c in super::escape_bytestring(self.bytes.as_ref()) {
|
||||
try!(f.write_char(c));
|
||||
}
|
||||
f.write_char('"')
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for ByteBuf {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for ByteBuf {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
ByteBuf::from(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Vec<u8>> for ByteBuf {
|
||||
fn as_ref(&self) -> &Vec<u8> {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ByteBuf {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<Vec<u8>> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for ByteBuf {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for ByteBuf {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
&self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::DerefMut for ByteBuf {
|
||||
fn deref_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.bytes[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Serialize for ByteBuf {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This type implements the `serde::de::Visitor` trait for a `ByteBuf`.
|
||||
pub struct ByteBufVisitor;
|
||||
|
||||
impl de::Visitor for ByteBufVisitor {
|
||||
type Value = ByteBuf;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::new())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
|
||||
where V: de::SeqVisitor
|
||||
{
|
||||
let len = cmp::min(visitor.size_hint().0, 4096);
|
||||
let mut values = Vec::with_capacity(len);
|
||||
|
||||
while let Some(value) = try!(visitor.visit()) {
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
Ok(ByteBuf::from(values))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
|
||||
where E: de::Error
|
||||
{
|
||||
Ok(ByteBuf::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Deserialize for ByteBuf {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
|
||||
where D: de::Deserializer
|
||||
{
|
||||
deserializer.deserialize_byte_buf(ByteBufVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[inline]
|
||||
fn escape_bytestring<'a>
|
||||
(bytes: &'a [u8])
|
||||
-> iter::FlatMap<slice::Iter<'a, u8>, char::EscapeDefault, fn(&u8) -> char::EscapeDefault> {
|
||||
fn f(b: &u8) -> char::EscapeDefault {
|
||||
char::from_u32(*b as u32).unwrap().escape_default()
|
||||
}
|
||||
bytes.iter().flat_map(f as fn(&u8) -> char::EscapeDefault)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,409 +0,0 @@
|
||||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Extracted from https://github.com/rust-num/num.
|
||||
|
||||
// Rust 1.5 is unhappy that this private module is undocumented.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use core::{usize, u8, u16, u32, u64};
|
||||
use core::{isize, i8, i16, i32, i64};
|
||||
use core::{f32, f64};
|
||||
use core::mem::size_of;
|
||||
|
||||
/// Numbers which have upper and lower bounds
|
||||
pub trait Bounded {
|
||||
// FIXME (#5527): These should be associated constants
|
||||
/// returns the smallest finite number this type can represent
|
||||
fn min_value() -> Self;
|
||||
/// returns the largest finite number this type can represent
|
||||
fn max_value() -> Self;
|
||||
}
|
||||
|
||||
macro_rules! bounded_impl {
|
||||
($t:ty, $min:expr, $max:expr) => {
|
||||
impl Bounded for $t {
|
||||
#[inline]
|
||||
fn min_value() -> $t { $min }
|
||||
|
||||
#[inline]
|
||||
fn max_value() -> $t { $max }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bounded_impl!(usize, usize::MIN, usize::MAX);
|
||||
bounded_impl!(u8, u8::MIN, u8::MAX);
|
||||
bounded_impl!(u16, u16::MIN, u16::MAX);
|
||||
bounded_impl!(u32, u32::MIN, u32::MAX);
|
||||
bounded_impl!(u64, u64::MIN, u64::MAX);
|
||||
|
||||
bounded_impl!(isize, isize::MIN, isize::MAX);
|
||||
bounded_impl!(i8, i8::MIN, i8::MAX);
|
||||
bounded_impl!(i16, i16::MIN, i16::MAX);
|
||||
bounded_impl!(i32, i32::MIN, i32::MAX);
|
||||
bounded_impl!(i64, i64::MIN, i64::MAX);
|
||||
|
||||
bounded_impl!(f32, f32::MIN, f32::MAX);
|
||||
bounded_impl!(f64, f64::MIN, f64::MAX);
|
||||
|
||||
/// A generic trait for converting a value to a number.
|
||||
pub trait ToPrimitive {
|
||||
/// Converts the value of `self` to an `isize`.
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> {
|
||||
self.to_i64().and_then(|x| x.to_isize())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i8`.
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> {
|
||||
self.to_i64().and_then(|x| x.to_i8())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i16`.
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> {
|
||||
self.to_i64().and_then(|x| x.to_i16())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i32`.
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> {
|
||||
self.to_i64().and_then(|x| x.to_i32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `i64`.
|
||||
fn to_i64(&self) -> Option<i64>;
|
||||
|
||||
/// Converts the value of `self` to a `usize`.
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
self.to_u64().and_then(|x| x.to_usize())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u8`.
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> {
|
||||
self.to_u64().and_then(|x| x.to_u8())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u16`.
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> {
|
||||
self.to_u64().and_then(|x| x.to_u16())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u32`.
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> {
|
||||
self.to_u64().and_then(|x| x.to_u32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `u64`.
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64>;
|
||||
|
||||
/// Converts the value of `self` to an `f32`.
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> {
|
||||
self.to_f64().and_then(|x| x.to_f32())
|
||||
}
|
||||
|
||||
/// Converts the value of `self` to an `f64`.
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> {
|
||||
self.to_i64().and_then(|x| x.to_f64())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int_to_int {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let n = $slf as i64;
|
||||
let min_value: $DstT = Bounded::min_value();
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if min_value as i64 <= n && n <= max_value as i64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int_to_uint {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
let zero: $SrcT = 0;
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if zero <= $slf && $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_int {
|
||||
($T:ty) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { impl_to_primitive_int_to_int!($T, isize, *self) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { impl_to_primitive_int_to_int!($T, i8, *self) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { impl_to_primitive_int_to_int!($T, i16, *self) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { impl_to_primitive_int_to_int!($T, i32, *self) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { impl_to_primitive_int_to_int!($T, i64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> { impl_to_primitive_int_to_uint!($T, usize, *self) }
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { impl_to_primitive_int_to_uint!($T, u8, *self) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { impl_to_primitive_int_to_uint!($T, u16, *self) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { impl_to_primitive_int_to_uint!($T, u32, *self) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { impl_to_primitive_int_to_uint!($T, u64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { Some(*self as f64) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_to_primitive_int! { isize }
|
||||
impl_to_primitive_int! { i8 }
|
||||
impl_to_primitive_int! { i16 }
|
||||
impl_to_primitive_int! { i32 }
|
||||
impl_to_primitive_int! { i64 }
|
||||
|
||||
macro_rules! impl_to_primitive_uint_to_int {
|
||||
($DstT:ty, $slf:expr) => (
|
||||
{
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_uint_to_uint {
|
||||
($SrcT:ty, $DstT:ty, $slf:expr) => (
|
||||
{
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let zero: $SrcT = 0;
|
||||
let max_value: $DstT = Bounded::max_value();
|
||||
if zero <= $slf && $slf as u64 <= max_value as u64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_uint {
|
||||
($T:ty) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { impl_to_primitive_uint_to_int!(isize, *self) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { impl_to_primitive_uint_to_int!(i8, *self) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { impl_to_primitive_uint_to_int!(i16, *self) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { impl_to_primitive_uint_to_int!(i32, *self) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { impl_to_primitive_uint_to_int!(i64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
impl_to_primitive_uint_to_uint!($T, usize, *self)
|
||||
}
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { impl_to_primitive_uint_to_uint!($T, u8, *self) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { impl_to_primitive_uint_to_uint!($T, u16, *self) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { impl_to_primitive_uint_to_uint!($T, u32, *self) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { impl_to_primitive_uint_to_uint!($T, u64, *self) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { Some(*self as f32) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { Some(*self as f64) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_to_primitive_uint! { usize }
|
||||
impl_to_primitive_uint! { u8 }
|
||||
impl_to_primitive_uint! { u16 }
|
||||
impl_to_primitive_uint! { u32 }
|
||||
impl_to_primitive_uint! { u64 }
|
||||
|
||||
macro_rules! impl_to_primitive_float_to_float {
|
||||
($SrcT:ident, $DstT:ident, $slf:expr) => (
|
||||
if size_of::<$SrcT>() <= size_of::<$DstT>() {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
let n = $slf as f64;
|
||||
let max_value: $SrcT = ::core::$SrcT::MAX;
|
||||
if -max_value as f64 <= n && n <= max_value as f64 {
|
||||
Some($slf as $DstT)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! impl_to_primitive_float {
|
||||
($T:ident) => (
|
||||
impl ToPrimitive for $T {
|
||||
#[inline]
|
||||
fn to_isize(&self) -> Option<isize> { Some(*self as isize) }
|
||||
#[inline]
|
||||
fn to_i8(&self) -> Option<i8> { Some(*self as i8) }
|
||||
#[inline]
|
||||
fn to_i16(&self) -> Option<i16> { Some(*self as i16) }
|
||||
#[inline]
|
||||
fn to_i32(&self) -> Option<i32> { Some(*self as i32) }
|
||||
#[inline]
|
||||
fn to_i64(&self) -> Option<i64> { Some(*self as i64) }
|
||||
|
||||
#[inline]
|
||||
fn to_usize(&self) -> Option<usize> { Some(*self as usize) }
|
||||
#[inline]
|
||||
fn to_u8(&self) -> Option<u8> { Some(*self as u8) }
|
||||
#[inline]
|
||||
fn to_u16(&self) -> Option<u16> { Some(*self as u16) }
|
||||
#[inline]
|
||||
fn to_u32(&self) -> Option<u32> { Some(*self as u32) }
|
||||
#[inline]
|
||||
fn to_u64(&self) -> Option<u64> { Some(*self as u64) }
|
||||
|
||||
#[inline]
|
||||
fn to_f32(&self) -> Option<f32> { impl_to_primitive_float_to_float!($T, f32, *self) }
|
||||
#[inline]
|
||||
fn to_f64(&self) -> Option<f64> { impl_to_primitive_float_to_float!($T, f64, *self) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_to_primitive_float! { f32 }
|
||||
impl_to_primitive_float! { f64 }
|
||||
|
||||
pub trait FromPrimitive: Sized {
|
||||
#[inline]
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
|
||||
fn from_i64(n: i64) -> Option<Self>;
|
||||
|
||||
#[inline]
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
FromPrimitive::from_u64(n as u64)
|
||||
}
|
||||
|
||||
fn from_u64(n: u64) -> Option<Self>;
|
||||
|
||||
#[inline]
|
||||
fn from_f32(n: f32) -> Option<Self> {
|
||||
FromPrimitive::from_f64(n as f64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_f64(n: f64) -> Option<Self> {
|
||||
FromPrimitive::from_i64(n as i64)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_from_primitive {
|
||||
($T:ty, $to_ty:ident) => (
|
||||
impl FromPrimitive for $T {
|
||||
#[inline] fn from_i8(n: i8) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i16(n: i16) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i32(n: i32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_i64(n: i64) -> Option<$T> { n.$to_ty() }
|
||||
|
||||
#[inline] fn from_u8(n: u8) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u16(n: u16) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u32(n: u32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_u64(n: u64) -> Option<$T> { n.$to_ty() }
|
||||
|
||||
#[inline] fn from_f32(n: f32) -> Option<$T> { n.$to_ty() }
|
||||
#[inline] fn from_f64(n: f64) -> Option<$T> { n.$to_ty() }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl_from_primitive! { isize, to_isize }
|
||||
impl_from_primitive! { i8, to_i8 }
|
||||
impl_from_primitive! { i16, to_i16 }
|
||||
impl_from_primitive! { i32, to_i32 }
|
||||
impl_from_primitive! { i64, to_i64 }
|
||||
impl_from_primitive! { usize, to_usize }
|
||||
impl_from_primitive! { u8, to_u8 }
|
||||
impl_from_primitive! { u16, to_u16 }
|
||||
impl_from_primitive! { u32, to_u32 }
|
||||
impl_from_primitive! { u64, to_u64 }
|
||||
impl_from_primitive! { f32, to_f32 }
|
||||
impl_from_primitive! { f64, to_f64 }
|
||||
@@ -0,0 +1,243 @@
|
||||
use lib::*;
|
||||
|
||||
use de::{
|
||||
Deserialize, Deserializer, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
|
||||
};
|
||||
|
||||
/// An efficient way of discarding data from a deserializer.
|
||||
///
|
||||
/// Think of this like `serde_json::Value` in that it can be deserialized from
|
||||
/// any type, except that it does not store any information about the data that
|
||||
/// gets deserialized.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// use std::fmt;
|
||||
/// use std::marker::PhantomData;
|
||||
///
|
||||
/// 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:
|
||||
/// ///
|
||||
/// /// ```
|
||||
/// /// NthElement::new(3).deserialize(deserializer)
|
||||
/// /// ```
|
||||
/// pub struct NthElement<T> {
|
||||
/// n: usize,
|
||||
/// marker: PhantomData<T>,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> NthElement<T> {
|
||||
/// pub fn new(n: usize) -> Self {
|
||||
/// NthElement {
|
||||
/// n: n,
|
||||
/// marker: PhantomData,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> Visitor<'de> for NthElement<T>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = T;
|
||||
///
|
||||
/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// write!(
|
||||
/// formatter,
|
||||
/// "a sequence in which we care about element {}",
|
||||
/// self.n
|
||||
/// )
|
||||
/// }
|
||||
///
|
||||
/// fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
/// where
|
||||
/// A: SeqAccess<'de>,
|
||||
/// {
|
||||
/// // Skip over the first `n` elements.
|
||||
/// for i in 0..self.n {
|
||||
/// // It is an error if the sequence ends before we get to element `n`.
|
||||
/// if seq.next_element::<IgnoredAny>()?.is_none() {
|
||||
/// return Err(de::Error::invalid_length(i, &self));
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Deserialize the one we care about.
|
||||
/// let nth = match seq.next_element()? {
|
||||
/// Some(nth) => nth,
|
||||
/// None => {
|
||||
/// return Err(de::Error::invalid_length(self.n, &self));
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// // Skip over any remaining elements in the sequence after `n`.
|
||||
/// while let Some(IgnoredAny) = seq.next_element()? {
|
||||
/// // ignore
|
||||
/// }
|
||||
///
|
||||
/// Ok(nth)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'de, T> DeserializeSeed<'de> for NthElement<T>
|
||||
/// where
|
||||
/// T: Deserialize<'de>,
|
||||
/// {
|
||||
/// type Value = T;
|
||||
///
|
||||
/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// deserializer.deserialize_seq(self)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error>
|
||||
/// # where
|
||||
/// # D: Deserializer<'de>,
|
||||
/// # {
|
||||
/// // Deserialize only the sequence element at index 3 from this deserializer.
|
||||
/// // The element at index 3 is required to be a string. Elements before and
|
||||
/// // after index 3 are allowed to be of any type.
|
||||
/// let s: String = NthElement::new(3).deserialize(deserializer)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct IgnoredAny;
|
||||
|
||||
impl<'de> Visitor<'de> for IgnoredAny {
|
||||
type Value = IgnoredAny;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("anything at all")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bool<E>(self, x: bool) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_i64<E>(self, x: i64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_i128<E>(self, x: i128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
serde_if_integer128! {
|
||||
#[inline]
|
||||
fn visit_u128<E>(self, x: u128) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> {
|
||||
let _ = x;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = s;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_none<E>(self) -> Result<Self::Value, E> {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
IgnoredAny::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
IgnoredAny::deserialize(deserializer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_unit<E>(self) -> Result<Self::Value, E> {
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(IgnoredAny) = try!(seq.next_element()) {
|
||||
// Gobble
|
||||
}
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: MapAccess<'de>,
|
||||
{
|
||||
while let Some((IgnoredAny, IgnoredAny)) = try!(map.next_entry()) {
|
||||
// Gobble
|
||||
}
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
let _ = bytes;
|
||||
Ok(IgnoredAny)
|
||||
}
|
||||
|
||||
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 {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<IgnoredAny, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_ignored_any(IgnoredAny)
|
||||
}
|
||||
}
|
||||
+2116
-755
File diff suppressed because it is too large
Load Diff
+1350
-686
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use de::{Deserialize, Deserializer, Error, Visitor};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
pub use de::content::{Content, ContentRefDeserializer, ContentDeserializer, TaggedContentVisitor,
|
||||
TagOrContentField, TagOrContentFieldVisitor, InternallyTaggedUnitVisitor,
|
||||
UntaggedUnitVisitor};
|
||||
|
||||
/// If the missing field is of type `Option<T>` then treat is as `None`,
|
||||
/// otherwise it is an error.
|
||||
pub fn missing_field<V, E>(field: &'static str) -> Result<V, E>
|
||||
where V: Deserialize,
|
||||
E: Error
|
||||
{
|
||||
struct MissingFieldDeserializer<E>(&'static str, PhantomData<E>);
|
||||
|
||||
impl<E> Deserializer for MissingFieldDeserializer<E>
|
||||
where E: Error
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn deserialize<V>(self, _visitor: V) -> Result<V::Value, E>
|
||||
where V: Visitor
|
||||
{
|
||||
Err(Error::missing_field(self.0))
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E>
|
||||
where V: Visitor
|
||||
{
|
||||
visitor.visit_none()
|
||||
}
|
||||
|
||||
forward_to_deserialize! {
|
||||
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
|
||||
seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
tuple_struct struct struct_field tuple enum ignored_any
|
||||
}
|
||||
}
|
||||
|
||||
let deserializer = MissingFieldDeserializer(field, PhantomData);
|
||||
Deserialize::deserialize(deserializer)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use de::{Deserialize, DeserializeSeed, Deserializer};
|
||||
|
||||
/// A DeserializeSeed helper for implementing deserialize_in_place Visitors.
|
||||
///
|
||||
/// Wraps a mutable reference and calls deserialize_in_place on it.
|
||||
pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T);
|
||||
|
||||
impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize_in_place(deserializer, self.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
use lib::*;
|
||||
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
||||
const MAX_ONE_B: u32 = 0x80;
|
||||
const MAX_TWO_B: u32 = 0x800;
|
||||
const MAX_THREE_B: u32 = 0x10000;
|
||||
|
||||
#[inline]
|
||||
pub fn encode(c: char) -> Encode {
|
||||
let code = c as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
Encode { buf: buf, pos: pos }
|
||||
}
|
||||
|
||||
pub struct Encode {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl Encode {
|
||||
pub fn as_str(&self) -> &str {
|
||||
str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
||||
+1069
-482
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
//! A stand-in for `std::error`
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
/// A stand-in for `std::error::Error`, which requires no allocation.
|
||||
pub trait Error: Debug + Display {
|
||||
/// A short description of the error.
|
||||
///
|
||||
/// The description should not contain newlines or sentence-ending
|
||||
/// punctuation, to facilitate embedding in larger user-facing
|
||||
/// strings.
|
||||
fn description(&self) -> &str;
|
||||
|
||||
/// The lower-level cause of this error, if any.
|
||||
fn cause(&self) -> Option<&Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::String;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::borrow::Cow;
|
||||
#[cfg(all(feature = "collections", not(feature = "std")))]
|
||||
use collections::borrow::Cow;
|
||||
|
||||
pub use core::default::Default;
|
||||
pub use core::fmt;
|
||||
pub use core::marker::PhantomData;
|
||||
pub use core::option::Option::{self, None, Some};
|
||||
pub use core::result::Result::{self, Ok, Err};
|
||||
|
||||
#[cfg(any(feature = "collections", feature = "std"))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
|
||||
// The generated code calls this like:
|
||||
//
|
||||
// let value = &_serde::export::from_utf8_lossy(bytes);
|
||||
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
|
||||
//
|
||||
// so it is okay for the return type to be different from the std case as long
|
||||
// as the above works.
|
||||
#[cfg(not(any(feature = "collections", feature = "std")))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
use core::str;
|
||||
// Three unicode replacement characters if it fails. They look like a
|
||||
// white-on-black question mark. The user will recognize it as invalid
|
||||
// UTF-8.
|
||||
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
|
||||
}
|
||||
@@ -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::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
/// use serde::{serde_if_integer128, Serializer};
|
||||
///
|
||||
/// impl Serializer for MySerializer {
|
||||
/// type Ok = ();
|
||||
/// type Error = Error;
|
||||
///
|
||||
/// fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// /* ... */
|
||||
///
|
||||
/// serde_if_integer128! {
|
||||
/// fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> {
|
||||
/// /* ... */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # serde::__serialize_unimplemented! {
|
||||
/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some
|
||||
/// # unit unit_struct unit_variant newtype_struct newtype_variant seq
|
||||
/// # tuple tuple_struct tuple_variant map struct struct_variant
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When Serde is built with support for 128-bit integers, this macro expands
|
||||
/// transparently into just the input tokens.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {
|
||||
/// $($tt)*
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// When built without support for 128-bit integers, this macro expands to
|
||||
/// nothing.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// macro_rules! serde_if_integer128 {
|
||||
/// ($($tt:tt)*) => {};
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg(integer128)]
|
||||
#[macro_export]
|
||||
macro_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {
|
||||
$($tt)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(integer128))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! serde_if_integer128 {
|
||||
($($tt:tt)*) => {};
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
//! Module that contains helper iterators.
|
||||
|
||||
use std::io;
|
||||
use std::iter::Peekable;
|
||||
|
||||
/// Iterator over a byte stream that tracks the current position's line and column.
|
||||
pub struct LineColIterator<Iter: Iterator<Item = io::Result<u8>>> {
|
||||
iter: Iter,
|
||||
line: usize,
|
||||
col: usize,
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Iter> {
|
||||
/// Construct a new `LineColIterator<Iter>`.
|
||||
pub fn new(iter: Iter) -> LineColIterator<Iter> {
|
||||
LineColIterator {
|
||||
iter: iter,
|
||||
line: 1,
|
||||
col: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Report the current line inside the iterator.
|
||||
pub fn line(&self) -> usize {
|
||||
self.line
|
||||
}
|
||||
|
||||
/// Report the current column inside the iterator.
|
||||
pub fn col(&self) -> usize {
|
||||
self.col
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying iterator.
|
||||
pub fn get_ref(&self) -> &Iter {
|
||||
&self.iter
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying iterator.
|
||||
pub fn get_mut(&mut self) -> &mut Iter {
|
||||
&mut self.iter
|
||||
}
|
||||
|
||||
/// Unwraps this `LineColIterator`, returning the underlying iterator.
|
||||
pub fn into_inner(self) -> Iter {
|
||||
self.iter
|
||||
}
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> LineColIterator<Peekable<Iter>> {
|
||||
/// peeks at the next value
|
||||
pub fn peek(&mut self) -> Option<&io::Result<u8>> {
|
||||
self.iter.peek()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Iter: Iterator<Item = io::Result<u8>>> Iterator for LineColIterator<Iter> {
|
||||
type Item = io::Result<u8>;
|
||||
fn next(&mut self) -> Option<io::Result<u8>> {
|
||||
match self.iter.next() {
|
||||
None => None,
|
||||
Some(Ok(b'\n')) => {
|
||||
self.line += 1;
|
||||
self.col = 0;
|
||||
Some(Ok(b'\n'))
|
||||
}
|
||||
Some(Ok(c)) => {
|
||||
self.col += 1;
|
||||
Some(Ok(c))
|
||||
}
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
+253
-64
@@ -9,99 +9,288 @@
|
||||
//! these two groups interact with each other, allowing any supported data
|
||||
//! structure to be serialized and deserialized using any supported data format.
|
||||
//!
|
||||
//! See the Serde website https://serde.rs/ for additional documentation and
|
||||
//! See the Serde website <https://serde.rs/> for additional documentation and
|
||||
//! usage examples.
|
||||
//!
|
||||
//! ### Design
|
||||
//! ## Design
|
||||
//!
|
||||
//! Where many other languages rely on runtime reflection for serializing data,
|
||||
//! Serde is instead built on Rust's powerful trait system. A data structure
|
||||
//! that knows how to serialize and deserialize itself is one that implements
|
||||
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's code
|
||||
//! generation to automatically derive implementations at compile time). This
|
||||
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
|
||||
//! attribute to automatically generate implementations at compile time). This
|
||||
//! avoids any overhead of reflection or runtime type information. In fact in
|
||||
//! many situations the interaction between data structure and data format can
|
||||
//! be completely optimized away by the Rust compiler, leaving Serde
|
||||
//! serialization to perform roughly the same speed as a handwritten serializer
|
||||
//! for the specific selection of data structure and data format.
|
||||
//! serialization to perform the same speed as a handwritten serializer for the
|
||||
//! specific selection of data structure and data format.
|
||||
//!
|
||||
//! ### Data formats
|
||||
//! ## Data formats
|
||||
//!
|
||||
//! The following is a partial list of data formats that have been implemented
|
||||
//! for Serde by the community.
|
||||
//!
|
||||
//! - [JSON](https://github.com/serde-rs/json), the ubiquitous JavaScript Object
|
||||
//! Notation used by many HTTP APIs.
|
||||
//! - [Bincode](https://github.com/TyOverby/bincode), a compact binary format
|
||||
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
|
||||
//! - [Bincode], a compact binary format
|
||||
//! used for IPC within the Servo rendering engine.
|
||||
//! - [CBOR](https://github.com/pyfisch/cbor), a Concise Binary Object
|
||||
//! Representation designed for small message size without the need for
|
||||
//! version negotiation.
|
||||
//! - [YAML](https://github.com/dtolnay/serde-yaml), a popular human-friendly
|
||||
//! configuration language that ain't markup language.
|
||||
//! - [MessagePack](https://github.com/3Hren/msgpack-rust), an efficient binary
|
||||
//! format that resembles a compact JSON.
|
||||
//! - [TOML](https://github.com/alexcrichton/toml-rs), a minimal configuration
|
||||
//! format used by [Cargo](http://doc.crates.io/manifest.html).
|
||||
//! - [Pickle](https://github.com/birkenfeld/serde-pickle), a format common in
|
||||
//! the Python world.
|
||||
//! - [Hjson](https://github.com/laktak/hjson-rust), a variant of JSON designed
|
||||
//! to be readable and writable by humans.
|
||||
//! - [BSON](https://github.com/zonyitoo/bson-rs), the data storage and network
|
||||
//! transfer format used by MongoDB.
|
||||
//! - [URL](https://github.com/nox/serde_urlencoded), the x-www-form-urlencoded
|
||||
//! format.
|
||||
//! - [XML](https://github.com/serde-rs/xml), the flexible machine-friendly W3C
|
||||
//! standard. *(deserialization only)*
|
||||
//! - [Envy](https://github.com/softprops/envy), a way to deserialize
|
||||
//! environment variables into Rust structs. *(deserialization only)*
|
||||
//! - [Redis](https://github.com/OneSignal/serde-redis), deserialize values from
|
||||
//! Redis when using [redis-rs](https://crates.io/crates/redis).
|
||||
//! - [CBOR], a Concise Binary Object Representation designed for small message
|
||||
//! size without the need for version negotiation.
|
||||
//! - [YAML], a 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.
|
||||
//! - [RON], a Rusty Object Notation.
|
||||
//! - [BSON], the data storage and network transfer format used by MongoDB.
|
||||
//! - [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)*
|
||||
//! - [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.
|
||||
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
|
||||
//! and from DynamoDB.
|
||||
//!
|
||||
//! [JSON]: https://github.com/serde-rs/json
|
||||
//! [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
|
||||
//! [RON]: https://github.com/ron-rs/ron
|
||||
//! [BSON]: https://github.com/zonyitoo/bson-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
|
||||
//! [Envy Store]: https://github.com/softprops/envy-store
|
||||
//! [Cargo]: http://doc.crates.io/manifest.html
|
||||
//! [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
|
||||
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
|
||||
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb
|
||||
|
||||
#![doc(html_root_url="https://docs.serde.rs")]
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Serde types in rustdoc of other crates get linked to here.
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.129")]
|
||||
// Support using Serde without the standard library!
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(feature = "unstable", feature(inclusive_range, nonzero, specialization, zero_one))]
|
||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
||||
#![cfg_attr(feature = "collections", feature(collections))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(linkedlist, type_complexity, doc_markdown))]
|
||||
#![deny(missing_docs)]
|
||||
// Unstable functionality only if the user asks for it. For tracking and
|
||||
// discussion of these features please refer to this issue:
|
||||
//
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(never_type))]
|
||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Ignored clippy and clippy_pedantic lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
// 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,
|
||||
let_underscore_drop,
|
||||
map_err_ignore,
|
||||
result_unit_err,
|
||||
wildcard_imports,
|
||||
// not practical
|
||||
needless_pass_by_value,
|
||||
similar_names,
|
||||
too_many_lines,
|
||||
// preference
|
||||
doc_markdown,
|
||||
unseparated_literal_suffix,
|
||||
// false positive
|
||||
needless_doctest_main,
|
||||
// noisy
|
||||
missing_errors_doc,
|
||||
must_use_candidate,
|
||||
)
|
||||
)]
|
||||
// Rustc lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
extern crate collections;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "unstable")]
|
||||
extern crate core as actual_core;
|
||||
/// A facade around all the types we need from the `std`, `core`, and `alloc`
|
||||
/// crates. This avoids elaborate import wrangling having to happen in every
|
||||
/// module.
|
||||
mod lib {
|
||||
mod core {
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use core::*;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod core {
|
||||
pub use std::{ops, hash, fmt, cmp, marker, mem, i8, i16, i32, i64, u8, u16, u32, u64, isize,
|
||||
usize, f32, f64, char, str, num, slice, iter, cell, default, result, option};
|
||||
#[cfg(feature = "unstable")]
|
||||
pub use actual_core::nonzero;
|
||||
pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
|
||||
pub use self::core::{f32, f64};
|
||||
pub use self::core::{i16, i32, i64, i8, isize};
|
||||
pub use self::core::{u16, u32, u64, u8, usize};
|
||||
|
||||
pub use self::core::cell::{Cell, RefCell};
|
||||
pub use self::core::clone::{self, Clone};
|
||||
pub use self::core::convert::{self, From, Into};
|
||||
pub use self::core::default::{self, Default};
|
||||
pub use self::core::fmt::{self, Debug, Display};
|
||||
pub use self::core::marker::{self, PhantomData};
|
||||
pub use self::core::num::Wrapping;
|
||||
pub use self::core::ops::Range;
|
||||
pub use self::core::option::{self, Option};
|
||||
pub use self::core::result::{self, Result};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::borrow::{Cow, ToOwned};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::borrow::{Cow, ToOwned};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::string::{String, ToString};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::vec::Vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::vec::Vec;
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::boxed::Box;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::boxed::Box;
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::rc::{Rc, Weak as RcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::rc::{Rc, Weak as RcWeak};
|
||||
|
||||
#[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::sync::{Arc, Weak as ArcWeak};
|
||||
#[cfg(all(feature = "rc", feature = "std"))]
|
||||
pub use std::sync::{Arc, Weak as ArcWeak};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::{error, net};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::ffi::{CStr, CString, OsStr, OsString};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::hash::{BuildHasher, Hash};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::Write;
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::sync::{Mutex, RwLock};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[cfg(all(feature = "std", collections_bound))]
|
||||
pub use std::collections::Bound;
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
||||
#[doc(inline)]
|
||||
pub use ser::{Serialize, Serializer};
|
||||
#[doc(inline)]
|
||||
pub use de::{Deserialize, Deserializer};
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod bytes;
|
||||
pub mod de;
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
pub mod iter;
|
||||
pub mod ser;
|
||||
#[cfg_attr(feature = "std", doc(hidden))]
|
||||
pub mod error;
|
||||
mod utils;
|
||||
#[macro_use]
|
||||
mod integer128;
|
||||
|
||||
// Generated code uses these to support no_std. Not public API.
|
||||
pub mod de;
|
||||
pub mod ser;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use de::{Deserialize, Deserializer};
|
||||
#[doc(inline)]
|
||||
pub use ser::{Serialize, Serializer};
|
||||
|
||||
// Used by generated code and doc tests. Not public API.
|
||||
#[doc(hidden)]
|
||||
pub mod export;
|
||||
#[path = "private/mod.rs"]
|
||||
pub mod __private;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use self::__private as export;
|
||||
#[allow(unused_imports)]
|
||||
use self::__private as private;
|
||||
|
||||
#[path = "de/seed.rs"]
|
||||
mod seed;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod std_error;
|
||||
|
||||
// Re-export #[derive(Serialize, Deserialize)].
|
||||
//
|
||||
// The reason re-exporting is not enabled by default is that disabling it would
|
||||
// be annoying for crates that provide handwritten impls or data formats. They
|
||||
// would need to disable default features and then explicitly re-enable std.
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[cfg(feature = "serde_derive")]
|
||||
#[doc(hidden)]
|
||||
pub use serde_derive::*;
|
||||
|
||||
+198
-184
@@ -1,123 +1,3 @@
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_method {
|
||||
($func:ident($($arg:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::std::result::Result<__V::Value, Self::Error>
|
||||
where __V: $crate::de::Visitor
|
||||
{
|
||||
self.deserialize(visitor)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_method {
|
||||
($func:ident($($arg:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<__V>(self, $(_: $arg,)* visitor: __V) -> ::core::result::Result<__V::Value, Self::Error>
|
||||
where __V: $crate::de::Visitor
|
||||
{
|
||||
self.deserialize(visitor)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_helper {
|
||||
(bool) => {
|
||||
forward_to_deserialize_method!{deserialize_bool()}
|
||||
};
|
||||
(u8) => {
|
||||
forward_to_deserialize_method!{deserialize_u8()}
|
||||
};
|
||||
(u16) => {
|
||||
forward_to_deserialize_method!{deserialize_u16()}
|
||||
};
|
||||
(u32) => {
|
||||
forward_to_deserialize_method!{deserialize_u32()}
|
||||
};
|
||||
(u64) => {
|
||||
forward_to_deserialize_method!{deserialize_u64()}
|
||||
};
|
||||
(i8) => {
|
||||
forward_to_deserialize_method!{deserialize_i8()}
|
||||
};
|
||||
(i16) => {
|
||||
forward_to_deserialize_method!{deserialize_i16()}
|
||||
};
|
||||
(i32) => {
|
||||
forward_to_deserialize_method!{deserialize_i32()}
|
||||
};
|
||||
(i64) => {
|
||||
forward_to_deserialize_method!{deserialize_i64()}
|
||||
};
|
||||
(f32) => {
|
||||
forward_to_deserialize_method!{deserialize_f32()}
|
||||
};
|
||||
(f64) => {
|
||||
forward_to_deserialize_method!{deserialize_f64()}
|
||||
};
|
||||
(char) => {
|
||||
forward_to_deserialize_method!{deserialize_char()}
|
||||
};
|
||||
(str) => {
|
||||
forward_to_deserialize_method!{deserialize_str()}
|
||||
};
|
||||
(string) => {
|
||||
forward_to_deserialize_method!{deserialize_string()}
|
||||
};
|
||||
(unit) => {
|
||||
forward_to_deserialize_method!{deserialize_unit()}
|
||||
};
|
||||
(option) => {
|
||||
forward_to_deserialize_method!{deserialize_option()}
|
||||
};
|
||||
(seq) => {
|
||||
forward_to_deserialize_method!{deserialize_seq()}
|
||||
};
|
||||
(seq_fixed_size) => {
|
||||
forward_to_deserialize_method!{deserialize_seq_fixed_size(usize)}
|
||||
};
|
||||
(bytes) => {
|
||||
forward_to_deserialize_method!{deserialize_bytes()}
|
||||
};
|
||||
(byte_buf) => {
|
||||
forward_to_deserialize_method!{deserialize_byte_buf()}
|
||||
};
|
||||
(map) => {
|
||||
forward_to_deserialize_method!{deserialize_map()}
|
||||
};
|
||||
(unit_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_unit_struct(&'static str)}
|
||||
};
|
||||
(newtype_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_newtype_struct(&'static str)}
|
||||
};
|
||||
(tuple_struct) => {
|
||||
forward_to_deserialize_method!{deserialize_tuple_struct(&'static str, usize)}
|
||||
};
|
||||
(struct) => {
|
||||
forward_to_deserialize_method!{deserialize_struct(&'static str, &'static [&'static str])}
|
||||
};
|
||||
(struct_field) => {
|
||||
forward_to_deserialize_method!{deserialize_struct_field()}
|
||||
};
|
||||
(tuple) => {
|
||||
forward_to_deserialize_method!{deserialize_tuple(usize)}
|
||||
};
|
||||
(enum) => {
|
||||
forward_to_deserialize_method!{deserialize_enum(&'static str, &'static [&'static str])}
|
||||
};
|
||||
(ignored_any) => {
|
||||
forward_to_deserialize_method!{deserialize_ignored_any()}
|
||||
};
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -125,98 +5,232 @@ macro_rules! forward_to_deserialize_helper {
|
||||
/// Helper macro when implementing the `Deserializer` part of a new data format
|
||||
/// for Serde.
|
||||
///
|
||||
/// Some `Deserializer` implementations for self-describing formats do not care
|
||||
/// what hint the `Visitor` gives them, they just want to blindly call the
|
||||
/// `Visitor` method corresponding to the data they can tell is in the input.
|
||||
/// This requires repetitive implementations of all the `Deserializer` trait
|
||||
/// methods.
|
||||
/// Some [`Deserializer`] implementations for self-describing formats do not
|
||||
/// care what hint the [`Visitor`] gives them, they just want to blindly call
|
||||
/// the [`Visitor`] method corresponding to the data they can tell is in the
|
||||
/// input. This requires repetitive implementations of all the [`Deserializer`]
|
||||
/// trait methods.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde;
|
||||
/// ```edition2018
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// # pub struct MyDeserializer;
|
||||
/// # impl Deserializer for MyDeserializer {
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
/// #
|
||||
/// # impl<'de> Deserializer<'de> for MyDeserializer {
|
||||
/// # type Error = value::Error;
|
||||
/// # fn deserialize<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where V: Visitor
|
||||
/// # { unimplemented!() }
|
||||
/// #
|
||||
/// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
|
||||
/// # where
|
||||
/// # V: Visitor<'de>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// #[inline]
|
||||
/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// self.deserialize(visitor)
|
||||
/// self.deserialize_any(visitor)
|
||||
/// }
|
||||
/// # forward_to_deserialize! {
|
||||
/// # u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
|
||||
/// # seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
/// # tuple_struct struct struct_field tuple enum ignored_any
|
||||
/// #
|
||||
/// # forward_to_deserialize_any! {
|
||||
/// # i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
/// # bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
/// # tuple_struct map struct enum identifier ignored_any
|
||||
/// # }
|
||||
/// # }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// The `forward_to_deserialize!` macro implements these simple forwarding
|
||||
/// methods so that they forward directly to `Deserializer::deserialize`. You
|
||||
/// can choose which methods to forward.
|
||||
/// The `forward_to_deserialize_any!` macro implements these simple forwarding
|
||||
/// methods so that they forward directly to [`Deserializer::deserialize_any`].
|
||||
/// You can choose which methods to forward.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate serde;
|
||||
/// ```edition2018
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// # pub struct MyDeserializer;
|
||||
/// impl Deserializer for MyDeserializer {
|
||||
/// #
|
||||
/// # struct MyDeserializer;
|
||||
/// #
|
||||
/// impl<'de> Deserializer<'de> for MyDeserializer {
|
||||
/// # type Error = value::Error;
|
||||
/// fn deserialize<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where V: Visitor
|
||||
/// #
|
||||
/// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
/// where
|
||||
/// V: Visitor<'de>,
|
||||
/// {
|
||||
/// /* ... */
|
||||
/// # let _ = visitor;
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// forward_to_deserialize! {
|
||||
/// bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
|
||||
/// seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
|
||||
/// tuple_struct struct struct_field tuple enum ignored_any
|
||||
/// forward_to_deserialize_any! {
|
||||
/// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
/// bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
/// tuple_struct map struct enum identifier ignored_any
|
||||
/// }
|
||||
/// }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize {
|
||||
///
|
||||
/// The macro assumes the convention that your `Deserializer` lifetime parameter
|
||||
/// is called `'de` and that the `Visitor` type parameters on each method are
|
||||
/// called `V`. A different type parameter and a different lifetime can be
|
||||
/// specified explicitly if necessary.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use std::marker::PhantomData;
|
||||
/// #
|
||||
/// # use serde::forward_to_deserialize_any;
|
||||
/// # use serde::de::{value, Deserializer, Visitor};
|
||||
/// #
|
||||
/// # struct MyDeserializer<V>(PhantomData<V>);
|
||||
/// #
|
||||
/// # impl<'q, V> Deserializer<'q> for MyDeserializer<V> {
|
||||
/// # type Error = value::Error;
|
||||
/// #
|
||||
/// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error>
|
||||
/// # where
|
||||
/// # W: Visitor<'q>,
|
||||
/// # {
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
/// #
|
||||
/// forward_to_deserialize_any! {
|
||||
/// <W: Visitor<'q>>
|
||||
/// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
|
||||
/// bytes byte_buf option unit unit_struct newtype_struct seq tuple
|
||||
/// tuple_struct map struct enum identifier ignored_any
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Deserializer`]: trait.Deserializer.html
|
||||
/// [`Visitor`]: de/trait.Visitor.html
|
||||
/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any
|
||||
#[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>})*
|
||||
};
|
||||
// This case must be after the previous one.
|
||||
($($func:ident)*) => {
|
||||
$(forward_to_deserialize_helper!{$func})*
|
||||
$(forward_to_deserialize_any_helper!{$func<'de, V>})*
|
||||
};
|
||||
}
|
||||
|
||||
/// Seralize the `$value` that implements Display as a string,
|
||||
/// when that string is statically known to never have more than
|
||||
/// a constant `$MAX_LEN` bytes.
|
||||
///
|
||||
/// Panics if the Display impl tries to write more than `$MAX_LEN` bytes.
|
||||
#[cfg(feature = "std")]
|
||||
// Not exported
|
||||
macro_rules! serialize_display_bounded_length {
|
||||
($value: expr, $MAX_LEN: expr, $serializer: expr) => {
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! forward_to_deserialize_any_method {
|
||||
($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => {
|
||||
#[inline]
|
||||
fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::__private::Result<$v::Value, Self::Error>
|
||||
where
|
||||
$v: $crate::de::Visitor<$l>,
|
||||
{
|
||||
use std::io::Write;
|
||||
let mut buffer: [u8; $MAX_LEN] = unsafe { ::std::mem::uninitialized() };
|
||||
let remaining_len;
|
||||
{
|
||||
let mut remaining = &mut buffer[..];
|
||||
write!(remaining, "{}", $value).unwrap();
|
||||
remaining_len = remaining.len()
|
||||
}
|
||||
let written_len = buffer.len() - remaining_len;
|
||||
let written = &buffer[..written_len];
|
||||
|
||||
// write! only provides std::fmt::Formatter to Display implementations,
|
||||
// which has methods write_str and write_char but no method to write arbitrary bytes.
|
||||
// Therefore, `written` is well-formed in UTF-8.
|
||||
let written_str = unsafe {
|
||||
::std::str::from_utf8_unchecked(written)
|
||||
};
|
||||
$serializer.serialize_str(written_str)
|
||||
$(
|
||||
let _ = $arg;
|
||||
)*
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! forward_to_deserialize_any_helper {
|
||||
(bool<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()}
|
||||
};
|
||||
(i8<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i8<$l, $v>()}
|
||||
};
|
||||
(i16<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i16<$l, $v>()}
|
||||
};
|
||||
(i32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i32<$l, $v>()}
|
||||
};
|
||||
(i64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()}
|
||||
};
|
||||
(i128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()}
|
||||
}
|
||||
};
|
||||
(u8<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()}
|
||||
};
|
||||
(u16<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u16<$l, $v>()}
|
||||
};
|
||||
(u32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u32<$l, $v>()}
|
||||
};
|
||||
(u64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()}
|
||||
};
|
||||
(u128<$l:tt, $v:ident>) => {
|
||||
serde_if_integer128! {
|
||||
forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()}
|
||||
}
|
||||
};
|
||||
(f32<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()}
|
||||
};
|
||||
(f64<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_f64<$l, $v>()}
|
||||
};
|
||||
(char<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_char<$l, $v>()}
|
||||
};
|
||||
(str<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_str<$l, $v>()}
|
||||
};
|
||||
(string<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_string<$l, $v>()}
|
||||
};
|
||||
(bytes<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_bytes<$l, $v>()}
|
||||
};
|
||||
(byte_buf<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_byte_buf<$l, $v>()}
|
||||
};
|
||||
(option<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_option<$l, $v>()}
|
||||
};
|
||||
(unit<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_unit<$l, $v>()}
|
||||
};
|
||||
(unit_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_unit_struct<$l, $v>(name: &'static str)}
|
||||
};
|
||||
(newtype_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_newtype_struct<$l, $v>(name: &'static str)}
|
||||
};
|
||||
(seq<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_seq<$l, $v>()}
|
||||
};
|
||||
(tuple<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_tuple<$l, $v>(len: usize)}
|
||||
};
|
||||
(tuple_struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_tuple_struct<$l, $v>(name: &'static str, len: usize)}
|
||||
};
|
||||
(map<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_map<$l, $v>()}
|
||||
};
|
||||
(struct<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_struct<$l, $v>(name: &'static str, fields: &'static [&'static str])}
|
||||
};
|
||||
(enum<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_enum<$l, $v>(name: &'static str, variants: &'static [&'static str])}
|
||||
};
|
||||
(identifier<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_identifier<$l, $v>()}
|
||||
};
|
||||
(ignored_any<$l:tt, $v:ident>) => {
|
||||
forward_to_deserialize_any_method!{deserialize_ignored_any<$l, $v>()}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,159 @@
|
||||
// Used only by Serde doc tests. Not public API.
|
||||
|
||||
use lib::*;
|
||||
|
||||
use ser;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
pub struct Error;
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T>(_: T) -> Self
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __private_serialize {
|
||||
() => {
|
||||
trait Serialize {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: $crate::Serializer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! __serialize_unimplemented {
|
||||
($($func:ident)*) => {
|
||||
$(
|
||||
__serialize_unimplemented_helper!($func);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __serialize_unimplemented_method {
|
||||
($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => {
|
||||
fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::__private::Result<Self::$ret, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! __serialize_unimplemented_helper {
|
||||
(bool) => {
|
||||
__serialize_unimplemented_method!(serialize_bool(bool) -> Ok);
|
||||
};
|
||||
(i8) => {
|
||||
__serialize_unimplemented_method!(serialize_i8(i8) -> Ok);
|
||||
};
|
||||
(i16) => {
|
||||
__serialize_unimplemented_method!(serialize_i16(i16) -> Ok);
|
||||
};
|
||||
(i32) => {
|
||||
__serialize_unimplemented_method!(serialize_i32(i32) -> Ok);
|
||||
};
|
||||
(i64) => {
|
||||
__serialize_unimplemented_method!(serialize_i64(i64) -> Ok);
|
||||
};
|
||||
(u8) => {
|
||||
__serialize_unimplemented_method!(serialize_u8(u8) -> Ok);
|
||||
};
|
||||
(u16) => {
|
||||
__serialize_unimplemented_method!(serialize_u16(u16) -> Ok);
|
||||
};
|
||||
(u32) => {
|
||||
__serialize_unimplemented_method!(serialize_u32(u32) -> Ok);
|
||||
};
|
||||
(u64) => {
|
||||
__serialize_unimplemented_method!(serialize_u64(u64) -> Ok);
|
||||
};
|
||||
(f32) => {
|
||||
__serialize_unimplemented_method!(serialize_f32(f32) -> Ok);
|
||||
};
|
||||
(f64) => {
|
||||
__serialize_unimplemented_method!(serialize_f64(f64) -> Ok);
|
||||
};
|
||||
(char) => {
|
||||
__serialize_unimplemented_method!(serialize_char(char) -> Ok);
|
||||
};
|
||||
(str) => {
|
||||
__serialize_unimplemented_method!(serialize_str(&str) -> Ok);
|
||||
};
|
||||
(bytes) => {
|
||||
__serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok);
|
||||
};
|
||||
(none) => {
|
||||
__serialize_unimplemented_method!(serialize_none() -> Ok);
|
||||
};
|
||||
(some) => {
|
||||
__serialize_unimplemented_method!(serialize_some<T>(&T) -> Ok);
|
||||
};
|
||||
(unit) => {
|
||||
__serialize_unimplemented_method!(serialize_unit() -> Ok);
|
||||
};
|
||||
(unit_struct) => {
|
||||
__serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok);
|
||||
};
|
||||
(unit_variant) => {
|
||||
__serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok);
|
||||
};
|
||||
(newtype_struct) => {
|
||||
__serialize_unimplemented_method!(serialize_newtype_struct<T>(&str, &T) -> Ok);
|
||||
};
|
||||
(newtype_variant) => {
|
||||
__serialize_unimplemented_method!(serialize_newtype_variant<T>(&str, u32, &str, &T) -> Ok);
|
||||
};
|
||||
(seq) => {
|
||||
type SerializeSeq = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_seq(Option<usize>) -> SerializeSeq);
|
||||
};
|
||||
(tuple) => {
|
||||
type SerializeTuple = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple);
|
||||
};
|
||||
(tuple_struct) => {
|
||||
type SerializeTupleStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct);
|
||||
};
|
||||
(tuple_variant) => {
|
||||
type SerializeTupleVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant);
|
||||
};
|
||||
(map) => {
|
||||
type SerializeMap = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_map(Option<usize>) -> SerializeMap);
|
||||
};
|
||||
(struct) => {
|
||||
type SerializeStruct = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct);
|
||||
};
|
||||
(struct_variant) => {
|
||||
type SerializeStructVariant = $crate::ser::Impossible<Self::Ok, Self::Error>;
|
||||
__serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#[cfg(serde_derive)]
|
||||
pub mod de;
|
||||
#[cfg(serde_derive)]
|
||||
pub mod ser;
|
||||
|
||||
pub mod size_hint;
|
||||
|
||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||
pub mod doc;
|
||||
|
||||
pub use lib::clone::Clone;
|
||||
pub use lib::convert::{From, Into};
|
||||
pub use lib::default::Default;
|
||||
pub use lib::fmt::{self, Formatter};
|
||||
pub use lib::marker::PhantomData;
|
||||
pub use lib::option::Option::{self, None, Some};
|
||||
pub use lib::ptr;
|
||||
pub use lib::result::Result::{self, Err, Ok};
|
||||
|
||||
pub use self::string::from_utf8_lossy;
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub use lib::{ToString, Vec};
|
||||
|
||||
#[cfg(core_try_from)]
|
||||
pub use lib::convert::TryFrom;
|
||||
|
||||
mod string {
|
||||
use lib::*;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> {
|
||||
String::from_utf8_lossy(bytes)
|
||||
}
|
||||
|
||||
// The generated code calls this like:
|
||||
//
|
||||
// let value = &_serde::__private::from_utf8_lossy(bytes);
|
||||
// Err(_serde::de::Error::unknown_variant(value, VARIANTS))
|
||||
//
|
||||
// so it is okay for the return type to be different from the std case as long
|
||||
// as the above works.
|
||||
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
||||
pub fn from_utf8_lossy(bytes: &[u8]) -> &str {
|
||||
// Three unicode replacement characters if it fails. They look like a
|
||||
// white-on-black question mark. The user will recognize it as invalid
|
||||
// UTF-8.
|
||||
str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}")
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
use lib::*;
|
||||
|
||||
pub fn from_bounds<I>(iter: &I) -> Option<usize>
|
||||
where
|
||||
I: Iterator,
|
||||
{
|
||||
helper(iter.size_hint())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[inline]
|
||||
pub fn cautious(hint: Option<usize>) -> usize {
|
||||
cmp::min(hint.unwrap_or(0), 4096)
|
||||
}
|
||||
|
||||
fn helper(bounds: (usize, Option<usize>)) -> Option<usize> {
|
||||
match bounds {
|
||||
(lower, Some(upper)) if lower == upper => Some(upper),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1,635 +0,0 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(all(not(feature = "std"), feature = "collections"))]
|
||||
use collections::{String, Vec};
|
||||
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[cfg(feature = "collections")]
|
||||
use collections::borrow::ToOwned;
|
||||
|
||||
use ser::{self, Serialize, Serializer};
|
||||
|
||||
pub struct SerializeTupleVariantAsMapValue<M> {
|
||||
map: M,
|
||||
name: &'static str,
|
||||
fields: Vec<Content>,
|
||||
}
|
||||
|
||||
impl<M> SerializeTupleVariantAsMapValue<M> {
|
||||
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
||||
SerializeTupleVariantAsMapValue {
|
||||
map: map,
|
||||
name: name,
|
||||
fields: Vec::with_capacity(len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M>
|
||||
where M: ser::SerializeMap
|
||||
{
|
||||
type Ok = M::Ok;
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), M::Error>
|
||||
{
|
||||
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||
try!(self.map.serialize_value(&Content::TupleStruct(self.name, self.fields)));
|
||||
self.map.end()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SerializeStructVariantAsMapValue<M> {
|
||||
map: M,
|
||||
name: &'static str,
|
||||
fields: Vec<(&'static str, Content)>,
|
||||
}
|
||||
|
||||
impl<M> SerializeStructVariantAsMapValue<M> {
|
||||
pub fn new(map: M, name: &'static str, len: usize) -> Self {
|
||||
SerializeStructVariantAsMapValue {
|
||||
map: map,
|
||||
name: name,
|
||||
fields: Vec::with_capacity(len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M>
|
||||
where M: ser::SerializeMap
|
||||
{
|
||||
type Ok = M::Ok;
|
||||
type Error = M::Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
key: &'static str,
|
||||
value: &T)
|
||||
-> Result<(), M::Error>
|
||||
{
|
||||
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
|
||||
self.fields.push((key, value));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(mut self) -> Result<M::Ok, M::Error> {
|
||||
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
|
||||
self.map.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Content {
|
||||
Bool(bool),
|
||||
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
|
||||
Char(char),
|
||||
String(String),
|
||||
Bytes(Vec<u8>),
|
||||
|
||||
None,
|
||||
Some(Box<Content>),
|
||||
|
||||
Unit,
|
||||
UnitStruct(&'static str),
|
||||
UnitVariant(&'static str, usize, &'static str),
|
||||
NewtypeStruct(&'static str, Box<Content>),
|
||||
NewtypeVariant(&'static str, usize, &'static str, Box<Content>),
|
||||
|
||||
Seq(Vec<Content>),
|
||||
SeqFixedSize(Vec<Content>),
|
||||
Tuple(Vec<Content>),
|
||||
TupleStruct(&'static str, Vec<Content>),
|
||||
TupleVariant(&'static str, usize, &'static str, Vec<Content>),
|
||||
Map(Vec<(Content, Content)>),
|
||||
Struct(&'static str, Vec<(&'static str, Content)>),
|
||||
StructVariant(&'static str, usize, &'static str, Vec<(&'static str, Content)>),
|
||||
}
|
||||
|
||||
impl Serialize for Content {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
match *self {
|
||||
Content::Bool(b) => serializer.serialize_bool(b),
|
||||
Content::U8(u) => serializer.serialize_u8(u),
|
||||
Content::U16(u) => serializer.serialize_u16(u),
|
||||
Content::U32(u) => serializer.serialize_u32(u),
|
||||
Content::U64(u) => serializer.serialize_u64(u),
|
||||
Content::I8(i) => serializer.serialize_i8(i),
|
||||
Content::I16(i) => serializer.serialize_i16(i),
|
||||
Content::I32(i) => serializer.serialize_i32(i),
|
||||
Content::I64(i) => serializer.serialize_i64(i),
|
||||
Content::F32(f) => serializer.serialize_f32(f),
|
||||
Content::F64(f) => serializer.serialize_f64(f),
|
||||
Content::Char(c) => serializer.serialize_char(c),
|
||||
Content::String(ref s) => serializer.serialize_str(s),
|
||||
Content::Bytes(ref b) => serializer.serialize_bytes(b),
|
||||
Content::None => serializer.serialize_none(),
|
||||
Content::Some(ref c) => serializer.serialize_some(&**c),
|
||||
Content::Unit => serializer.serialize_unit(),
|
||||
Content::UnitStruct(n) => serializer.serialize_unit_struct(n),
|
||||
Content::UnitVariant(n, i, v) => serializer.serialize_unit_variant(n, i, v),
|
||||
Content::NewtypeStruct(n, ref c) => serializer.serialize_newtype_struct(n, &**c),
|
||||
Content::NewtypeVariant(n, i, v, ref c) => serializer.serialize_newtype_variant(n, i, v, &**c),
|
||||
Content::Seq(ref elements) => elements.serialize(serializer),
|
||||
Content::SeqFixedSize(ref elements) => {
|
||||
use ser::SerializeSeq;
|
||||
let mut seq = try!(serializer.serialize_seq_fixed_size(elements.len()));
|
||||
for e in elements {
|
||||
try!(seq.serialize_element(e));
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
Content::Tuple(ref elements) => {
|
||||
use ser::SerializeTuple;
|
||||
let mut tuple = try!(serializer.serialize_tuple(elements.len()));
|
||||
for e in elements {
|
||||
try!(tuple.serialize_element(e));
|
||||
}
|
||||
tuple.end()
|
||||
}
|
||||
Content::TupleStruct(n, ref fields) => {
|
||||
use ser::SerializeTupleStruct;
|
||||
let mut ts = try!(serializer.serialize_tuple_struct(n, fields.len()));
|
||||
for f in fields {
|
||||
try!(ts.serialize_field(f));
|
||||
}
|
||||
ts.end()
|
||||
}
|
||||
Content::TupleVariant(n, i, v, ref fields) => {
|
||||
use ser::SerializeTupleVariant;
|
||||
let mut tv = try!(serializer.serialize_tuple_variant(n, i, v, fields.len()));
|
||||
for f in fields {
|
||||
try!(tv.serialize_field(f));
|
||||
}
|
||||
tv.end()
|
||||
}
|
||||
Content::Map(ref entries) => {
|
||||
use ser::SerializeMap;
|
||||
let mut map = try!(serializer.serialize_map(Some(entries.len())));
|
||||
for &(ref k, ref v) in entries {
|
||||
try!(map.serialize_entry(k, v));
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
Content::Struct(n, ref fields) => {
|
||||
use ser::SerializeStruct;
|
||||
let mut s = try!(serializer.serialize_struct(n, fields.len()));
|
||||
for &(k, ref v) in fields {
|
||||
try!(s.serialize_field(k, v));
|
||||
}
|
||||
s.end()
|
||||
}
|
||||
Content::StructVariant(n, i, v, ref fields) => {
|
||||
use ser::SerializeStructVariant;
|
||||
let mut sv = try!(serializer.serialize_struct_variant(n, i, v, fields.len()));
|
||||
for &(k, ref v) in fields {
|
||||
try!(sv.serialize_field(k, v));
|
||||
}
|
||||
sv.end()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentSerializer<E> {
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ContentSerializer<E> {
|
||||
fn new() -> Self {
|
||||
ContentSerializer {
|
||||
error: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Serializer for ContentSerializer<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
type SerializeSeq = SerializeSeq<E>;
|
||||
type SerializeTuple = SerializeTuple<E>;
|
||||
type SerializeTupleStruct = SerializeTupleStruct<E>;
|
||||
type SerializeTupleVariant = SerializeTupleVariant<E>;
|
||||
type SerializeMap = SerializeMap<E>;
|
||||
type SerializeStruct = SerializeStruct<E>;
|
||||
type SerializeStructVariant = SerializeStructVariant<E>;
|
||||
|
||||
fn serialize_bool(self, v: bool) -> Result<Content, E> {
|
||||
Ok(Content::Bool(v))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<Content, E> {
|
||||
Ok(Content::I8(v))
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<Content, E> {
|
||||
Ok(Content::I16(v))
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<Content, E> {
|
||||
Ok(Content::I32(v))
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Content, E> {
|
||||
Ok(Content::I64(v))
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<Content, E> {
|
||||
Ok(Content::U8(v))
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<Content, E> {
|
||||
Ok(Content::U16(v))
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<Content, E> {
|
||||
Ok(Content::U32(v))
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<Content, E> {
|
||||
Ok(Content::U64(v))
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<Content, E> {
|
||||
Ok(Content::F32(v))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<Content, E> {
|
||||
Ok(Content::F64(v))
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<Content, E> {
|
||||
Ok(Content::Char(v))
|
||||
}
|
||||
|
||||
fn serialize_str(self, value: &str) -> Result<Content, E> {
|
||||
Ok(Content::String(value.to_owned()))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, value: &[u8]) -> Result<Content, E> {
|
||||
Ok(Content::Bytes(value.to_owned()))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Content, E> {
|
||||
Ok(Content::None)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized + Serialize>(self,
|
||||
value: &T)
|
||||
-> Result<Content, E> {
|
||||
Ok(Content::Some(Box::new(try!(value.serialize(self)))))
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Content, E> {
|
||||
Ok(Content::Unit)
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self,
|
||||
name: &'static str)
|
||||
-> Result<Content, E> {
|
||||
Ok(Content::UnitStruct(name))
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self,
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str)
|
||||
-> Result<Content, E> {
|
||||
Ok(Content::UnitVariant(name, variant_index, variant))
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized + Serialize>(self,
|
||||
name: &'static str,
|
||||
value: &T)
|
||||
-> Result<Content, E> {
|
||||
Ok(Content::NewtypeStruct(name, Box::new(try!(value.serialize(self)))))
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized + Serialize>(self,
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str,
|
||||
value: &T)
|
||||
-> Result<Content, E> {
|
||||
Ok(Content::NewtypeVariant(name, variant_index, variant, Box::new(try!(value.serialize(self)))))
|
||||
}
|
||||
|
||||
fn serialize_seq(self,
|
||||
len: Option<usize>)
|
||||
-> Result<Self::SerializeSeq, E> {
|
||||
Ok(SerializeSeq {
|
||||
fixed_size: false,
|
||||
elements: Vec::with_capacity(len.unwrap_or(0)),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_seq_fixed_size(self,
|
||||
size: usize)
|
||||
-> Result<Self::SerializeSeq, E> {
|
||||
Ok(SerializeSeq {
|
||||
fixed_size: true,
|
||||
elements: Vec::with_capacity(size),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple(self,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeTuple, E> {
|
||||
Ok(SerializeTuple {
|
||||
elements: Vec::with_capacity(len),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self,
|
||||
name: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeTupleStruct, E> {
|
||||
Ok(SerializeTupleStruct {
|
||||
name: name,
|
||||
fields: Vec::with_capacity(len),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(self,
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeTupleVariant, E> {
|
||||
Ok(SerializeTupleVariant {
|
||||
name: name,
|
||||
variant_index: variant_index,
|
||||
variant: variant,
|
||||
fields: Vec::with_capacity(len),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_map(self,
|
||||
len: Option<usize>)
|
||||
-> Result<Self::SerializeMap, E> {
|
||||
Ok(SerializeMap {
|
||||
entries: Vec::with_capacity(len.unwrap_or(0)),
|
||||
key: None,
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct(self,
|
||||
name: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeStruct, E> {
|
||||
Ok(SerializeStruct {
|
||||
name: name,
|
||||
fields: Vec::with_capacity(len),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(self,
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeStructVariant, E> {
|
||||
Ok(SerializeStructVariant {
|
||||
name: name,
|
||||
variant_index: variant_index,
|
||||
variant: variant,
|
||||
fields: Vec::with_capacity(len),
|
||||
error: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeSeq<E> {
|
||||
fixed_size: bool,
|
||||
elements: Vec<Content>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeSeq for SerializeSeq<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.elements.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(if self.fixed_size {
|
||||
Content::SeqFixedSize(self.elements)
|
||||
} else {
|
||||
Content::Seq(self.elements)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTuple<E> {
|
||||
elements: Vec<Content>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeTuple for SerializeTuple<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.elements.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::Tuple(self.elements))
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTupleStruct<E> {
|
||||
name: &'static str,
|
||||
fields: Vec<Content>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::TupleStruct(self.name, self.fields))
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeTupleVariant<E> {
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str,
|
||||
fields: Vec<Content>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::TupleVariant(self.name, self.variant_index, self.variant, self.fields))
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeMap<E> {
|
||||
entries: Vec<(Content, Content)>,
|
||||
key: Option<Content>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeMap for SerializeMap<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_key<T: ?Sized + Serialize>(&mut self,
|
||||
key: &T)
|
||||
-> Result<(), E> {
|
||||
let key = try!(key.serialize(ContentSerializer::<E>::new()));
|
||||
self.key = Some(key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized + Serialize>(&mut self,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let key = self.key.take().expect("serialize_value called before serialize_key");
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.entries.push((key, value));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::Map(self.entries))
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized + Serialize, V: ?Sized + Serialize>(&mut self,
|
||||
key: &K,
|
||||
value: &V)
|
||||
-> Result<(), E> {
|
||||
let key = try!(key.serialize(ContentSerializer::<E>::new()));
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.entries.push((key, value));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeStruct<E> {
|
||||
name: &'static str,
|
||||
fields: Vec<(&'static str, Content)>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeStruct for SerializeStruct<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
key: &'static str,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push((key, value));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::Struct(self.name, self.fields))
|
||||
}
|
||||
}
|
||||
|
||||
struct SerializeStructVariant<E> {
|
||||
name: &'static str,
|
||||
variant_index: usize,
|
||||
variant: &'static str,
|
||||
fields: Vec<(&'static str, Content)>,
|
||||
error: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E> ser::SerializeStructVariant for SerializeStructVariant<E>
|
||||
where E: ser::Error
|
||||
{
|
||||
type Ok = Content;
|
||||
type Error = E;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
key: &'static str,
|
||||
value: &T)
|
||||
-> Result<(), E> {
|
||||
let value = try!(value.serialize(ContentSerializer::<E>::new()));
|
||||
self.fields.push((key, value));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Content, E> {
|
||||
Ok(Content::StructVariant(self.name, self.variant_index, self.variant, self.fields))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
+711
-499
File diff suppressed because it is too large
Load Diff
+111
-51
@@ -1,19 +1,26 @@
|
||||
//! This module contains `Impossible` serializer and its implementations.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use lib::*;
|
||||
|
||||
use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
|
||||
SerializeTupleVariant, SerializeMap, SerializeStruct, SerializeStructVariant};
|
||||
use ser::{
|
||||
self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
|
||||
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
|
||||
};
|
||||
|
||||
/// Helper type for implementing a `Serializer` that does not support
|
||||
/// serializing one of the compound types.
|
||||
///
|
||||
/// This type cannot be instantiated, but implements every one of the traits
|
||||
/// corresponding to the `Serializer` compound types: `SerializeSeq`,
|
||||
/// `SerializeTuple`, `SerializeTupleStruct`, `SerializeTupleVariant`,
|
||||
/// `SerializeMap`, `SerializeStruct`, and `SerializeStructVariant`.
|
||||
/// corresponding to the [`Serializer`] compound types: [`SerializeSeq`],
|
||||
/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`],
|
||||
/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`].
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```edition2018
|
||||
/// # use serde::ser::{Serializer, Impossible};
|
||||
/// # use serde::__private::doc::Error;
|
||||
/// #
|
||||
/// # struct MySerializer;
|
||||
/// #
|
||||
/// impl Serializer for MySerializer {
|
||||
/// type Ok = ();
|
||||
/// type Error = Error;
|
||||
@@ -27,130 +34,183 @@ use ser::{self, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
|
||||
/// -> Result<Self::SerializeSeq, Error> {
|
||||
/// // Given Impossible cannot be instantiated, the only
|
||||
/// // thing we can do here is to return an error.
|
||||
/// # stringify! {
|
||||
/// Err(...)
|
||||
/// # };
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// /* other Serializer methods */
|
||||
/// # 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
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Impossible<Ok, E> {
|
||||
///
|
||||
/// [`Serializer`]: trait.Serializer.html
|
||||
/// [`SerializeSeq`]: trait.SerializeSeq.html
|
||||
/// [`SerializeTuple`]: trait.SerializeTuple.html
|
||||
/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html
|
||||
/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html
|
||||
/// [`SerializeMap`]: trait.SerializeMap.html
|
||||
/// [`SerializeStruct`]: trait.SerializeStruct.html
|
||||
/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html
|
||||
pub struct Impossible<Ok, Error> {
|
||||
void: Void,
|
||||
_marker: PhantomData<(Ok, E)>,
|
||||
ok: PhantomData<Ok>,
|
||||
error: PhantomData<Error>,
|
||||
}
|
||||
|
||||
enum Void {}
|
||||
|
||||
impl<Ok, E> SerializeSeq for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeSeq for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTuple for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTuple for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTupleStruct for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTupleStruct for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeTupleVariant for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeTupleVariant for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeMap for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeMap for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), E> {
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized + Serialize>(&mut self, _value: &T) -> Result<(), E> {
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeStruct for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeStruct for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T)
|
||||
-> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ok, E> SerializeStructVariant for Impossible<Ok, E>
|
||||
where E: ser::Error
|
||||
impl<Ok, Error> SerializeStructVariant for Impossible<Ok, Error>
|
||||
where
|
||||
Error: ser::Error,
|
||||
{
|
||||
type Ok = Ok;
|
||||
type Error = E;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T)
|
||||
-> Result<(), E> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let _ = key;
|
||||
let _ = value;
|
||||
match self.void {}
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Ok, E> {
|
||||
fn end(self) -> Result<Ok, Error> {
|
||||
match self.void {}
|
||||
}
|
||||
}
|
||||
|
||||
+1503
-365
File diff suppressed because it is too large
Load Diff
@@ -1,313 +0,0 @@
|
||||
use core::fmt::{self, Display};
|
||||
|
||||
use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
use ser::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};
|
||||
|
||||
/// Not public API.
|
||||
pub fn serialize_tagged_newtype<S, T>(serializer: S,
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
tag: &'static str,
|
||||
variant_name: &'static str,
|
||||
value: &T)
|
||||
-> Result<S::Ok, S::Error>
|
||||
where S: Serializer,
|
||||
T: Serialize
|
||||
{
|
||||
value.serialize(TaggedSerializer {
|
||||
type_ident: type_ident,
|
||||
variant_ident: variant_ident,
|
||||
tag: tag,
|
||||
variant_name: variant_name,
|
||||
delegate: serializer,
|
||||
})
|
||||
}
|
||||
|
||||
struct TaggedSerializer<S> {
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
tag: &'static str,
|
||||
variant_name: &'static str,
|
||||
delegate: S,
|
||||
}
|
||||
|
||||
enum Unsupported {
|
||||
Boolean,
|
||||
Integer,
|
||||
Float,
|
||||
Char,
|
||||
String,
|
||||
ByteArray,
|
||||
Optional,
|
||||
Unit,
|
||||
UnitStruct,
|
||||
Sequence,
|
||||
Tuple,
|
||||
TupleStruct,
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
Enum,
|
||||
}
|
||||
|
||||
impl Display for Unsupported {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Unsupported::Boolean => formatter.write_str("a boolean"),
|
||||
Unsupported::Integer => formatter.write_str("an integer"),
|
||||
Unsupported::Float => formatter.write_str("a float"),
|
||||
Unsupported::Char => formatter.write_str("a char"),
|
||||
Unsupported::String => formatter.write_str("a string"),
|
||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||
Unsupported::Optional => formatter.write_str("an optional"),
|
||||
Unsupported::Unit => formatter.write_str("unit"),
|
||||
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
|
||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
Unsupported::Enum => formatter.write_str("an enum"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Error {
|
||||
type_ident: &'static str,
|
||||
variant_ident: &'static str,
|
||||
ty: Unsupported,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter,
|
||||
"cannot serialize tagged newtype variant {}::{} containing {}",
|
||||
self.type_ident, self.variant_ident, self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> TaggedSerializer<S>
|
||||
where S: Serializer
|
||||
{
|
||||
fn bad_type(self, what: Unsupported) -> S::Error {
|
||||
ser::Error::custom(Error {
|
||||
type_ident: self.type_ident,
|
||||
variant_ident: self.variant_ident,
|
||||
ty: what,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Serializer for TaggedSerializer<S>
|
||||
where S: Serializer
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
|
||||
type SerializeSeq = Impossible<S::Ok, S::Error>;
|
||||
type SerializeTuple = Impossible<S::Ok, S::Error>;
|
||||
type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
|
||||
type SerializeMap = S::SerializeMap;
|
||||
type SerializeStruct = S::SerializeStruct;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
type SerializeStructVariant = Impossible<S::Ok, S::Error>;
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;
|
||||
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Boolean))
|
||||
}
|
||||
|
||||
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Integer))
|
||||
}
|
||||
|
||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Float))
|
||||
}
|
||||
|
||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Char))
|
||||
}
|
||||
|
||||
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::String))
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::ByteArray))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
Err(self.bad_type(Unsupported::Optional))
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Unit))
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::UnitStruct))
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
inner_variant: &'static str)
|
||||
-> Result<Self::Ok, Self::Error> {
|
||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
try!(map.serialize_entry(inner_variant, &()));
|
||||
map.end()
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(self,
|
||||
_: &'static str,
|
||||
value: &T)
|
||||
-> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
inner_variant: &'static str,
|
||||
inner_value: &T)
|
||||
-> Result<Self::Ok, Self::Error>
|
||||
where T: Serialize
|
||||
{
|
||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
try!(map.serialize_entry(inner_variant, inner_value));
|
||||
map.end()
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Sequence))
|
||||
}
|
||||
|
||||
fn serialize_seq_fixed_size(self, _: usize) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Sequence))
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::Tuple))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(self.bad_type(Unsupported::TupleStruct))
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
fn serialize_tuple_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
// Lack of push-based serialization means we need to buffer the content
|
||||
// of the tuple variant, so it requires std.
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn serialize_tuple_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
inner_variant: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
try!(map.serialize_key(inner_variant));
|
||||
Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len))
|
||||
}
|
||||
|
||||
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
fn serialize_struct(self,
|
||||
name: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeStruct, Self::Error> {
|
||||
let mut state = try!(self.delegate.serialize_struct(name, len + 1));
|
||||
try!(state.serialize_field(self.tag, self.variant_name));
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "std", feature = "collections")))]
|
||||
fn serialize_struct_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
_: &'static str,
|
||||
_: usize)
|
||||
-> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
// Lack of push-based serialization means we need to buffer the content
|
||||
// of the struct variant, so it requires std.
|
||||
Err(self.bad_type(Unsupported::Enum))
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "collections"))]
|
||||
fn serialize_struct_variant(self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
inner_variant: &'static str,
|
||||
len: usize)
|
||||
-> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
let mut map = try!(self.delegate.serialize_map(Some(2)));
|
||||
try!(map.serialize_entry(self.tag, self.variant_name));
|
||||
try!(map.serialize_key(inner_variant));
|
||||
Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//! Private utility functions
|
||||
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
const TAG_THREE_B: u8 = 0b1110_0000;
|
||||
const TAG_FOUR_B: u8 = 0b1111_0000;
|
||||
const MAX_ONE_B: u32 = 0x80;
|
||||
const MAX_TWO_B: u32 = 0x800;
|
||||
const MAX_THREE_B: u32 = 0x10000;
|
||||
|
||||
#[inline]
|
||||
pub fn encode_utf8(c: char) -> EncodeUtf8 {
|
||||
let code = c as u32;
|
||||
let mut buf = [0; 4];
|
||||
let pos = if code < MAX_ONE_B {
|
||||
buf[3] = code as u8;
|
||||
3
|
||||
} else if code < MAX_TWO_B {
|
||||
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
2
|
||||
} else if code < MAX_THREE_B {
|
||||
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
1
|
||||
} else {
|
||||
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
||||
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
||||
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
|
||||
0
|
||||
};
|
||||
EncodeUtf8 {
|
||||
buf: buf,
|
||||
pos: pos,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EncodeUtf8 {
|
||||
buf: [u8; 4],
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl EncodeUtf8 {
|
||||
// FIXME: use this from_utf8_unchecked, since we know it can never fail
|
||||
pub fn as_str(&self) -> &str {
|
||||
::core::str::from_utf8(&self.buf[self.pos..]).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const Pattern_White_Space_table: &'static [(char, char)] = &[('\u{9}', '\u{d}'),
|
||||
('\u{20}', '\u{20}'),
|
||||
('\u{85}', '\u{85}'),
|
||||
('\u{200e}', '\u{200f}'),
|
||||
('\u{2028}', '\u{2029}')];
|
||||
|
||||
fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
r.binary_search_by(|&(lo, hi)| if c < lo {
|
||||
Greater
|
||||
} else if hi < c {
|
||||
Less
|
||||
} else {
|
||||
Equal
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Pattern_White_Space(c: char) -> bool {
|
||||
bsearch_range_table(c, Pattern_White_Space_table)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
[package]
|
||||
name = "serde_codegen_internals"
|
||||
version = "0.14.1"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = "AST representation used by Serde codegen. Unstable."
|
||||
homepage = "https://serde.rs"
|
||||
repository = "https://github.com/serde-rs/serde"
|
||||
documentation = "https://docs.serde.rs/serde_codegen_internals/"
|
||||
keywords = ["serde", "serialization"]
|
||||
readme = "../README.md"
|
||||
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "0.11", default-features = false, features = ["parsing"] }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
@@ -1 +0,0 @@
|
||||
../README.md
|
||||
@@ -1,122 +0,0 @@
|
||||
use syn;
|
||||
use attr;
|
||||
use Ctxt;
|
||||
|
||||
pub struct Item<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Item,
|
||||
pub body: Body<'a>,
|
||||
pub generics: &'a syn::Generics,
|
||||
}
|
||||
|
||||
pub enum Body<'a> {
|
||||
Enum(Vec<Variant<'a>>),
|
||||
Struct(Style, Vec<Field<'a>>),
|
||||
}
|
||||
|
||||
pub struct Variant<'a> {
|
||||
pub ident: syn::Ident,
|
||||
pub attrs: attr::Variant,
|
||||
pub style: Style,
|
||||
pub fields: Vec<Field<'a>>,
|
||||
}
|
||||
|
||||
pub struct Field<'a> {
|
||||
pub ident: Option<syn::Ident>,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Ty,
|
||||
}
|
||||
|
||||
pub enum Style {
|
||||
Struct,
|
||||
Tuple,
|
||||
Newtype,
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a> Item<'a> {
|
||||
pub fn from_ast(cx: &Ctxt, item: &'a syn::MacroInput) -> Item<'a> {
|
||||
let attrs = attr::Item::from_ast(cx, item);
|
||||
|
||||
let mut body = match item.body {
|
||||
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
|
||||
syn::Body::Struct(ref variant_data) => {
|
||||
let (style, fields) = struct_from_ast(cx, variant_data);
|
||||
Body::Struct(style, fields)
|
||||
}
|
||||
};
|
||||
|
||||
match body {
|
||||
Body::Enum(ref mut variants) => {
|
||||
for ref mut variant in variants {
|
||||
variant.attrs.rename_by_rule(attrs.rename_all());
|
||||
for ref mut field in &mut variant.fields {
|
||||
field.attrs.rename_by_rule(variant.attrs.rename_all());
|
||||
}
|
||||
}
|
||||
}
|
||||
Body::Struct(_, ref mut fields) => {
|
||||
for field in fields {
|
||||
field.attrs.rename_by_rule(attrs.rename_all());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
ident: item.ident.clone(),
|
||||
attrs: attrs,
|
||||
body: body,
|
||||
generics: &item.generics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Body<'a> {
|
||||
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
|
||||
match *self {
|
||||
Body::Enum(ref variants) => {
|
||||
Box::new(variants.iter()
|
||||
.flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Body::Struct(_, ref fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
|
||||
variants.iter()
|
||||
.map(|variant| {
|
||||
let (style, fields) = struct_from_ast(cx, &variant.data);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs: attr::Variant::from_ast(cx, variant),
|
||||
style: style,
|
||||
fields: fields,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData) -> (Style, Vec<Field<'a>>) {
|
||||
match *data {
|
||||
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields)),
|
||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
||||
(Style::Newtype, fields_from_ast(cx, fields))
|
||||
}
|
||||
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields)),
|
||||
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field]) -> Vec<Field<'a>> {
|
||||
fields.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
Field {
|
||||
ident: field.ident.clone(),
|
||||
attrs: attr::Field::from_ast(cx, i, field),
|
||||
ty: &field.ty,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -1,799 +0,0 @@
|
||||
use Ctxt;
|
||||
use syn;
|
||||
use syn::MetaItem::{List, NameValue, Word};
|
||||
use syn::NestedMetaItem::{Literal, MetaItem};
|
||||
use std::str::FromStr;
|
||||
|
||||
// This module handles parsing of `#[serde(...)]` attributes. The entrypoints
|
||||
// are `attr::Item::from_ast`, `attr::Variant::from_ast`, and
|
||||
// `attr::Field::from_ast`. Each returns an instance of the corresponding
|
||||
// struct. Note that none of them return a Result. Unrecognized, malformed, or
|
||||
// duplicated attributes result in a span_err but otherwise are ignored. The
|
||||
// user will see errors simultaneously for all bad attributes in the crate
|
||||
// rather than just the first.
|
||||
|
||||
pub use case::RenameRule;
|
||||
|
||||
struct Attr<'c, T> {
|
||||
cx: &'c Ctxt,
|
||||
name: &'static str,
|
||||
value: Option<T>,
|
||||
}
|
||||
|
||||
impl<'c, T> Attr<'c, T> {
|
||||
fn none(cx: &'c Ctxt, name: &'static str) -> Self {
|
||||
Attr {
|
||||
cx: cx,
|
||||
name: name,
|
||||
value: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, value: T) {
|
||||
if self.value.is_some() {
|
||||
self.cx.error(format!("duplicate serde attribute `{}`", self.name));
|
||||
} else {
|
||||
self.value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_opt(&mut self, value: Option<T>) {
|
||||
if let Some(value) = value {
|
||||
self.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_if_none(&mut self, value: T) {
|
||||
if self.value.is_none() {
|
||||
self.value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
fn get(self) -> Option<T> {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
struct BoolAttr<'c>(Attr<'c, ()>);
|
||||
|
||||
impl<'c> BoolAttr<'c> {
|
||||
fn none(cx: &'c Ctxt, name: &'static str) -> Self {
|
||||
BoolAttr(Attr::none(cx, name))
|
||||
}
|
||||
|
||||
fn set_true(&mut self) {
|
||||
self.0.set(());
|
||||
}
|
||||
|
||||
fn get(&self) -> bool {
|
||||
self.0.value.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Name {
|
||||
serialize: String,
|
||||
deserialize: String,
|
||||
}
|
||||
|
||||
impl Name {
|
||||
/// Return the container name for the container when serializing.
|
||||
pub fn serialize_name(&self) -> String {
|
||||
self.serialize.clone()
|
||||
}
|
||||
|
||||
/// Return the container name for the container when deserializing.
|
||||
pub fn deserialize_name(&self) -> String {
|
||||
self.deserialize.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents container (e.g. struct) attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Item {
|
||||
name: Name,
|
||||
deny_unknown_fields: bool,
|
||||
default: Default,
|
||||
rename_all: RenameRule,
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
tag: EnumTag,
|
||||
}
|
||||
|
||||
/// Styles of representing an enum.
|
||||
#[derive(Debug)]
|
||||
pub enum EnumTag {
|
||||
/// The default.
|
||||
///
|
||||
/// ```json
|
||||
/// {"variant1": {"key1": "value1", "key2": "value2"}}
|
||||
/// ```
|
||||
External,
|
||||
|
||||
/// `#[serde(tag = "type")]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"type": "variant1", "key1": "value1", "key2": "value2"}
|
||||
/// ```
|
||||
Internal { tag: String },
|
||||
|
||||
/// `#[serde(tag = "t", content = "c")]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
|
||||
/// ```
|
||||
Adjacent { tag: String, content: String },
|
||||
|
||||
/// `#[serde(untagged)]`
|
||||
///
|
||||
/// ```json
|
||||
/// {"key1": "value1", "key2": "value2"}
|
||||
/// ```
|
||||
None,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
/// Extract out the `#[serde(...)]` attributes from an item.
|
||||
pub fn from_ast(cx: &Ctxt, item: &syn::MacroInput) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
|
||||
let mut default = Attr::none(cx, "default");
|
||||
let mut rename_all = Attr::none(cx, "rename_all");
|
||||
let mut ser_bound = Attr::none(cx, "bound");
|
||||
let mut de_bound = Attr::none(cx, "bound");
|
||||
let mut untagged = BoolAttr::none(cx, "untagged");
|
||||
let mut internal_tag = Attr::none(cx, "tag");
|
||||
let mut content = Attr::none(cx, "content");
|
||||
|
||||
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename_all="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match RenameRule::from_str(&s) {
|
||||
Ok(rename_rule) => rename_all.set(rename_rule),
|
||||
Err(()) => {
|
||||
cx.error(format!("unknown rename rule for #[serde(rename_all \
|
||||
= {:?})]",
|
||||
s))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deny_unknown_fields)]`
|
||||
MetaItem(Word(ref name)) if name == "deny_unknown_fields" => {
|
||||
deny_unknown_fields.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(default)]`
|
||||
MetaItem(Word(ref name)) if name == "default" => {
|
||||
match item.body {
|
||||
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||
default.set(Default::Default);
|
||||
}
|
||||
_ => {
|
||||
cx.error("#[serde(default)] can only be used on structs \
|
||||
with named fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(default="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||
default.set(Default::Path(path));
|
||||
}
|
||||
_ => {
|
||||
cx.error("#[serde(default = \"...\")] can only be used \
|
||||
on structs with named fields")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
|
||||
if let Ok(where_predicates) =
|
||||
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_bound.set(where_predicates.clone());
|
||||
de_bound.set(where_predicates);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
|
||||
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
|
||||
ser_bound.set_opt(ser);
|
||||
de_bound.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(untagged)]`
|
||||
MetaItem(Word(ref name)) if name == "untagged" => {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
untagged.set_true();
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(untagged)] can only be used on enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(tag = "type")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "tag" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
internal_tag.set(s);
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(tag = \"...\")] can only be used on enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(content = "c")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "content" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match item.body {
|
||||
syn::Body::Enum(_) => {
|
||||
content.set(s);
|
||||
}
|
||||
syn::Body::Struct(_) => {
|
||||
cx.error("#[serde(content = \"...\")] can only be used on \
|
||||
enums")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde container attribute `{}`",
|
||||
meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde container attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tag = match (untagged.get(), internal_tag.get(), content.get()) {
|
||||
(false, None, None) => EnumTag::External,
|
||||
(true, None, None) => EnumTag::None,
|
||||
(false, Some(tag), None) => {
|
||||
// Check that there are no tuple variants.
|
||||
if let syn::Body::Enum(ref variants) = item.body {
|
||||
for variant in variants {
|
||||
match variant.data {
|
||||
syn::VariantData::Struct(_) |
|
||||
syn::VariantData::Unit => {}
|
||||
syn::VariantData::Tuple(ref fields) => {
|
||||
if fields.len() != 1 {
|
||||
cx.error("#[serde(tag = \"...\")] cannot be used with tuple \
|
||||
variants");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EnumTag::Internal { tag: tag }
|
||||
}
|
||||
(true, Some(_), None) => {
|
||||
cx.error("enum cannot be both untagged and internally tagged");
|
||||
EnumTag::External // doesn't matter, will error
|
||||
}
|
||||
(false, None, Some(_)) => {
|
||||
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
|
||||
EnumTag::External
|
||||
}
|
||||
(true, None, Some(_)) => {
|
||||
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
|
||||
EnumTag::External
|
||||
}
|
||||
(false, Some(tag), Some(content)) => {
|
||||
EnumTag::Adjacent {
|
||||
tag: tag,
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
(true, Some(_), Some(_)) => {
|
||||
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
|
||||
EnumTag::External
|
||||
}
|
||||
};
|
||||
|
||||
Item {
|
||||
name: Name {
|
||||
serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()),
|
||||
deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()),
|
||||
},
|
||||
deny_unknown_fields: deny_unknown_fields.get(),
|
||||
default: default.get().unwrap_or(Default::None),
|
||||
rename_all: rename_all.get().unwrap_or(RenameRule::None),
|
||||
ser_bound: ser_bound.get(),
|
||||
de_bound: de_bound.get(),
|
||||
tag: tag,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn rename_all(&self) -> &RenameRule {
|
||||
&self.rename_all
|
||||
}
|
||||
|
||||
pub fn deny_unknown_fields(&self) -> bool {
|
||||
self.deny_unknown_fields
|
||||
}
|
||||
|
||||
pub fn default(&self) -> &Default {
|
||||
&self.default
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> &EnumTag {
|
||||
&self.tag
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents variant attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Variant {
|
||||
name: Name,
|
||||
ser_renamed: bool,
|
||||
de_renamed: bool,
|
||||
rename_all: RenameRule,
|
||||
skip_deserializing: bool,
|
||||
skip_serializing: bool,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut rename_all = Attr::none(cx, "rename_all");
|
||||
|
||||
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename_all="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
match RenameRule::from_str(&s) {
|
||||
Ok(rename_rule) => rename_all.set(rename_rule),
|
||||
Err(()) => {
|
||||
cx.error(format!("unknown rename rule for #[serde(rename_all \
|
||||
= {:?})]",
|
||||
s))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_deserializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
|
||||
skip_deserializing.set_true();
|
||||
}
|
||||
// Parse `#[serde(skip_serializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_serializing" => {
|
||||
skip_serializing.set_true();
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde variant attribute `{}`", meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde variant attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ser_name = ser_name.get();
|
||||
let ser_renamed = ser_name.is_some();
|
||||
let de_name = de_name.get();
|
||||
let de_renamed = de_name.is_some();
|
||||
Variant {
|
||||
name: Name {
|
||||
serialize: ser_name.unwrap_or_else(|| variant.ident.to_string()),
|
||||
deserialize: de_name.unwrap_or_else(|| variant.ident.to_string()),
|
||||
},
|
||||
ser_renamed: ser_renamed,
|
||||
de_renamed: de_renamed,
|
||||
rename_all: rename_all.get().unwrap_or(RenameRule::None),
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing: skip_serializing.get(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn rename_by_rule(&mut self, rule: &RenameRule) {
|
||||
if !self.ser_renamed {
|
||||
self.name.serialize = rule.apply_to_variant(&self.name.serialize);
|
||||
}
|
||||
if !self.de_renamed {
|
||||
self.name.deserialize = rule.apply_to_variant(&self.name.deserialize);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rename_all(&self) -> &RenameRule {
|
||||
&self.rename_all
|
||||
}
|
||||
|
||||
pub fn skip_deserializing(&self) -> bool {
|
||||
self.skip_deserializing
|
||||
}
|
||||
|
||||
pub fn skip_serializing(&self) -> bool {
|
||||
self.skip_serializing
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents field attribute information
|
||||
#[derive(Debug)]
|
||||
pub struct Field {
|
||||
name: Name,
|
||||
ser_renamed: bool,
|
||||
de_renamed: bool,
|
||||
skip_serializing: bool,
|
||||
skip_deserializing: bool,
|
||||
skip_serializing_if: Option<syn::Path>,
|
||||
default: Default,
|
||||
serialize_with: Option<syn::Path>,
|
||||
deserialize_with: Option<syn::Path>,
|
||||
ser_bound: Option<Vec<syn::WherePredicate>>,
|
||||
de_bound: Option<Vec<syn::WherePredicate>>,
|
||||
}
|
||||
|
||||
/// Represents the default to use for a field when deserializing.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Default {
|
||||
/// Field must always be specified because it does not have a default.
|
||||
None,
|
||||
/// The default is given by `std::default::Default::default()`.
|
||||
Default,
|
||||
/// The default is given by this function.
|
||||
Path(syn::Path),
|
||||
}
|
||||
|
||||
impl Field {
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
|
||||
let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if");
|
||||
let mut default = Attr::none(cx, "default");
|
||||
let mut serialize_with = Attr::none(cx, "serialize_with");
|
||||
let mut deserialize_with = Attr::none(cx, "deserialize_with");
|
||||
let mut ser_bound = Attr::none(cx, "bound");
|
||||
let mut de_bound = Attr::none(cx, "bound");
|
||||
|
||||
let ident = match field.ident {
|
||||
Some(ref ident) => ident.to_string(),
|
||||
None => index.to_string(),
|
||||
};
|
||||
|
||||
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
|
||||
for meta_item in meta_items {
|
||||
match meta_item {
|
||||
// Parse `#[serde(rename="foo")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => {
|
||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_name.set(s.clone());
|
||||
de_name.set(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "rename" => {
|
||||
if let Ok((ser, de)) = get_renames(cx, meta_items) {
|
||||
ser_name.set_opt(ser);
|
||||
de_name.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(default)]`
|
||||
MetaItem(Word(ref name)) if name == "default" => {
|
||||
default.set(Default::Default);
|
||||
}
|
||||
|
||||
// Parse `#[serde(default="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "default" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
default.set(Default::Path(path));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_serializing" => {
|
||||
skip_serializing.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_deserializing)]`
|
||||
MetaItem(Word(ref name)) if name == "skip_deserializing" => {
|
||||
skip_deserializing.set_true();
|
||||
}
|
||||
|
||||
// Parse `#[serde(skip_serializing_if="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
skip_serializing_if.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(serialize_with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
serialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(deserialize_with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
deserialize_with.set(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(with="...")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "with" => {
|
||||
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) {
|
||||
let mut ser_path = path.clone();
|
||||
ser_path.segments.push("serialize".into());
|
||||
serialize_with.set(ser_path);
|
||||
let mut de_path = path;
|
||||
de_path.segments.push("deserialize".into());
|
||||
deserialize_with.set(de_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound="D: Serialize")]`
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => {
|
||||
if let Ok(where_predicates) =
|
||||
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) {
|
||||
ser_bound.set(where_predicates.clone());
|
||||
de_bound.set(where_predicates);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
|
||||
MetaItem(List(ref name, ref meta_items)) if name == "bound" => {
|
||||
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) {
|
||||
ser_bound.set_opt(ser);
|
||||
de_bound.set_opt(de);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(ref meta_item) => {
|
||||
cx.error(format!("unknown serde field attribute `{}`", meta_item.name()));
|
||||
}
|
||||
|
||||
Literal(_) => {
|
||||
cx.error("unexpected literal in serde field attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is skip_deserializing, initialize the field to Default::default()
|
||||
// unless a different default is specified by `#[serde(default="...")]`
|
||||
if skip_deserializing.0.value.is_some() {
|
||||
default.set_if_none(Default::Default);
|
||||
}
|
||||
|
||||
let ser_name = ser_name.get();
|
||||
let ser_renamed = ser_name.is_some();
|
||||
let de_name = de_name.get();
|
||||
let de_renamed = de_name.is_some();
|
||||
Field {
|
||||
name: Name {
|
||||
serialize: ser_name.unwrap_or_else(|| ident.clone()),
|
||||
deserialize: de_name.unwrap_or(ident),
|
||||
},
|
||||
ser_renamed: ser_renamed,
|
||||
de_renamed: de_renamed,
|
||||
skip_serializing: skip_serializing.get(),
|
||||
skip_deserializing: skip_deserializing.get(),
|
||||
skip_serializing_if: skip_serializing_if.get(),
|
||||
default: default.get().unwrap_or(Default::None),
|
||||
serialize_with: serialize_with.get(),
|
||||
deserialize_with: deserialize_with.get(),
|
||||
ser_bound: ser_bound.get(),
|
||||
de_bound: de_bound.get(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn rename_by_rule(&mut self, rule: &RenameRule) {
|
||||
if !self.ser_renamed {
|
||||
self.name.serialize = rule.apply_to_field(&self.name.serialize);
|
||||
}
|
||||
if !self.de_renamed {
|
||||
self.name.deserialize = rule.apply_to_field(&self.name.deserialize);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_serializing(&self) -> bool {
|
||||
self.skip_serializing
|
||||
}
|
||||
|
||||
pub fn skip_deserializing(&self) -> bool {
|
||||
self.skip_deserializing
|
||||
}
|
||||
|
||||
pub fn skip_serializing_if(&self) -> Option<&syn::Path> {
|
||||
self.skip_serializing_if.as_ref()
|
||||
}
|
||||
|
||||
pub fn default(&self) -> &Default {
|
||||
&self.default
|
||||
}
|
||||
|
||||
pub fn serialize_with(&self) -> Option<&syn::Path> {
|
||||
self.serialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn deserialize_with(&self) -> Option<&syn::Path> {
|
||||
self.deserialize_with.as_ref()
|
||||
}
|
||||
|
||||
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.ser_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
|
||||
pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> {
|
||||
self.de_bound.as_ref().map(|vec| &vec[..])
|
||||
}
|
||||
}
|
||||
|
||||
type SerAndDe<T> = (Option<T>, Option<T>);
|
||||
|
||||
fn get_ser_and_de<T, F>(cx: &Ctxt,
|
||||
attr_name: &'static str,
|
||||
items: &[syn::NestedMetaItem],
|
||||
f: F)
|
||||
-> Result<SerAndDe<T>, ()>
|
||||
where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>
|
||||
{
|
||||
let mut ser_item = Attr::none(cx, attr_name);
|
||||
let mut de_item = Attr::none(cx, attr_name);
|
||||
|
||||
for item in items {
|
||||
match *item {
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => {
|
||||
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
|
||||
ser_item.set(v);
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => {
|
||||
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) {
|
||||
de_item.set(v);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., \
|
||||
deserialize = ...)`",
|
||||
attr_name));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((ser_item.get(), de_item.get()))
|
||||
}
|
||||
|
||||
fn get_renames(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result<SerAndDe<String>, ()> {
|
||||
get_ser_and_de(cx, "rename", items, get_string_from_lit)
|
||||
}
|
||||
|
||||
fn get_where_predicates(cx: &Ctxt,
|
||||
items: &[syn::NestedMetaItem])
|
||||
-> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
|
||||
get_ser_and_de(cx, "bound", items, parse_lit_into_where)
|
||||
}
|
||||
|
||||
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMetaItem>> {
|
||||
match attr.value {
|
||||
List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string_from_lit(cx: &Ctxt,
|
||||
attr_name: &str,
|
||||
meta_item_name: &str,
|
||||
lit: &syn::Lit)
|
||||
-> Result<String, ()> {
|
||||
if let syn::Lit::Str(ref s, _) = *lit {
|
||||
Ok(s.clone())
|
||||
} else {
|
||||
cx.error(format!("expected serde {} attribute to be a string: `{} = \"...\"`",
|
||||
attr_name,
|
||||
meta_item_name));
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> {
|
||||
let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit));
|
||||
syn::parse_path(&string).map_err(|err| cx.error(err))
|
||||
}
|
||||
|
||||
fn parse_lit_into_where(cx: &Ctxt,
|
||||
attr_name: &str,
|
||||
meta_item_name: &str,
|
||||
lit: &syn::Lit)
|
||||
-> Result<Vec<syn::WherePredicate>, ()> {
|
||||
let string = try!(get_string_from_lit(cx, attr_name, meta_item_name, lit));
|
||||
if string.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let where_string = format!("where {}", string);
|
||||
|
||||
syn::parse_where_clause(&where_string).map(|wh| wh.predicates).map_err(|err| cx.error(err))
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
use std::ascii::AsciiExt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use self::RenameRule::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum RenameRule {
|
||||
/// Don't apply a default rename rule.
|
||||
None,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for enum variants.
|
||||
PascalCase,
|
||||
/// Rename direct children to "camelCase" style.
|
||||
CamelCase,
|
||||
/// Rename direct children to "snake_case" style, as commonly used for fields.
|
||||
SnakeCase,
|
||||
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly used for constants.
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
}
|
||||
|
||||
impl RenameRule {
|
||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||
SnakeCase => {
|
||||
let mut snake = String::new();
|
||||
for (i, ch) in variant.char_indices() {
|
||||
if i > 0 && ch.is_uppercase() {
|
||||
snake.push('_');
|
||||
}
|
||||
snake.push(ch.to_ascii_lowercase());
|
||||
}
|
||||
snake
|
||||
}
|
||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_to_field(&self, field: &str) -> String {
|
||||
match *self {
|
||||
None | SnakeCase => field.to_owned(),
|
||||
PascalCase => {
|
||||
let mut pascal = String::new();
|
||||
let mut capitalize = true;
|
||||
for ch in field.chars() {
|
||||
if ch == '_' {
|
||||
capitalize = true;
|
||||
} else if capitalize {
|
||||
pascal.push(ch.to_ascii_uppercase());
|
||||
capitalize = false;
|
||||
} else {
|
||||
pascal.push(ch);
|
||||
}
|
||||
}
|
||||
pascal
|
||||
}
|
||||
CamelCase => {
|
||||
let pascal = PascalCase.apply_to_field(field);
|
||||
pascal[..1].to_ascii_lowercase() + &pascal[1..]
|
||||
}
|
||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||
KebabCase => field.replace('_', "-"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RenameRule {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> {
|
||||
match rename_all_str {
|
||||
"PascalCase" => Ok(PascalCase),
|
||||
"camelCase" => Ok(CamelCase),
|
||||
"snake_case" => Ok(SnakeCase),
|
||||
"SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase),
|
||||
"kebab-case" => Ok(KebabCase),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, camel, snake, screaming, kebab) in
|
||||
&[("Outcome", "outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("VeryTasty", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty"),
|
||||
("A", "a", "a", "A", "a"),
|
||||
("Z42", "z42", "z42", "Z42", "z42")] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, pascal, camel, screaming, kebab) in
|
||||
&[("outcome", "Outcome", "outcome", "OUTCOME", "outcome"),
|
||||
("very_tasty", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty"),
|
||||
("a", "A", "a", "A", "a"),
|
||||
("z42", "Z42", "z42", "Z42", "z42")] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
use std::fmt::Display;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[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 self.errors.borrow().is_some() {
|
||||
panic!("forgot to check for errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
extern crate syn;
|
||||
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use ctxt::Ctxt;
|
||||
|
||||
mod case;
|
||||
+17
-13
@@ -1,27 +1,31 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "0.9.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
version = "1.0.129" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
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"]
|
||||
readme = "crates-io.md"
|
||||
include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[features]
|
||||
unstable = []
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
default = []
|
||||
deserialize_in_place = []
|
||||
|
||||
[lib]
|
||||
name = "serde_derive"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.3.8"
|
||||
serde_codegen_internals = { version = "=0.14.1", default-features = false, path = "../serde_codegen_internals" }
|
||||
syn = { version = "0.11", features = ["visit"] }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = "1.0.60"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
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");
|
||||
}
|
||||
|
||||
// The ptr::addr_of! macro stabilized in Rust 1.51:
|
||||
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
|
||||
if minor >= 51 {
|
||||
println!("cargo:rustc-cfg=ptr_addr_of");
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
+332
-152
@@ -1,77 +1,89 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use syn::{self, visit};
|
||||
use syn;
|
||||
use syn::punctuated::{Pair, Punctuated};
|
||||
|
||||
use internals::ast::Item;
|
||||
use internals::attr;
|
||||
use internals::ast::{Container, Data};
|
||||
use internals::{attr, ungroup};
|
||||
|
||||
macro_rules! path {
|
||||
($first:ident $(:: $rest:ident)*) => {
|
||||
syn::Path {
|
||||
global: false,
|
||||
segments: vec![
|
||||
stringify!($first).into(),
|
||||
$(
|
||||
stringify!($rest).into(),
|
||||
)*
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
(::$first:ident $(:: $rest:ident)*) => {
|
||||
syn::Path {
|
||||
global: true,
|
||||
segments: vec![
|
||||
stringify!($first).into(),
|
||||
$(
|
||||
stringify!($rest).into(),
|
||||
)*
|
||||
],
|
||||
}
|
||||
};
|
||||
}
|
||||
use proc_macro2::Span;
|
||||
|
||||
// Remove the default from every type parameter because in the generated impls
|
||||
// they look like associated types: "error: associated type bindings are not
|
||||
// allowed here".
|
||||
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
|
||||
syn::Generics {
|
||||
ty_params: generics.ty_params
|
||||
params: generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|ty_param| syn::TyParam { default: None, ..ty_param.clone() })
|
||||
.map(|param| match param {
|
||||
syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
|
||||
eq_token: None,
|
||||
default: None,
|
||||
..param.clone()
|
||||
}),
|
||||
_ => param.clone(),
|
||||
})
|
||||
.collect(),
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_where_predicates(generics: &syn::Generics,
|
||||
predicates: &[syn::WherePredicate])
|
||||
-> syn::Generics {
|
||||
pub fn with_where_predicates(
|
||||
generics: &syn::Generics,
|
||||
predicates: &[syn::WherePredicate],
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend_from_slice(predicates);
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.extend(predicates.iter().cloned());
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_where_predicates_from_fields<F>(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
from_field: F)
|
||||
-> syn::Generics
|
||||
where F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>
|
||||
{
|
||||
let predicates = item.body
|
||||
pub fn with_where_predicates_from_fields(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
|
||||
) -> syn::Generics {
|
||||
let predicates = cont
|
||||
.data
|
||||
.all_fields()
|
||||
.flat_map(|field| from_field(&field.attrs))
|
||||
.filter_map(|field| from_field(&field.attrs))
|
||||
.flat_map(|predicates| predicates.to_vec());
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(predicates);
|
||||
generics.make_where_clause().predicates.extend(predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_where_predicates_from_variants(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
|
||||
) -> syn::Generics {
|
||||
let variants = match &cont.data {
|
||||
Data::Enum(variants) => variants,
|
||||
Data::Struct(_, _) => {
|
||||
return generics.clone();
|
||||
}
|
||||
};
|
||||
|
||||
let predicates = variants
|
||||
.iter()
|
||||
.filter_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,
|
||||
@@ -79,24 +91,40 @@ pub fn with_where_predicates_from_fields<F>(item: &Item,
|
||||
// #[serde(skip_serializing)]
|
||||
// c: C,
|
||||
// }
|
||||
pub fn with_bound<F>(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
filter: F,
|
||||
bound: &syn::Path)
|
||||
-> syn::Generics
|
||||
where F: Fn(&attr::Field) -> bool
|
||||
{
|
||||
struct FindTyParams {
|
||||
pub fn with_bound(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics {
|
||||
struct FindTyParams<'ast> {
|
||||
// Set of all generic type parameters on the current struct (A, B, C in
|
||||
// the example). Initialized up front.
|
||||
all_ty_params: HashSet<syn::Ident>,
|
||||
all_type_params: HashSet<syn::Ident>,
|
||||
|
||||
// Set of generic type parameters used in fields for which filter
|
||||
// returns true (A and B in the example). Filled in as the visitor sees
|
||||
// them.
|
||||
relevant_ty_params: HashSet<syn::Ident>,
|
||||
relevant_type_params: HashSet<syn::Ident>,
|
||||
|
||||
// Fields whose type is an associated type of one of the generic type
|
||||
// parameters.
|
||||
associated_type_usage: Vec<&'ast syn::TypePath>,
|
||||
}
|
||||
impl visit::Visitor for FindTyParams {
|
||||
fn visit_path(&mut self, path: &syn::Path) {
|
||||
|
||||
impl<'ast> FindTyParams<'ast> {
|
||||
fn visit_field(&mut self, field: &'ast syn::Field) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.visit_type(&field.ty);
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'ast syn::Path) {
|
||||
if let Some(seg) = path.segments.last() {
|
||||
if seg.ident == "PhantomData" {
|
||||
// Hardcoded exception, because PhantomData<T> implements
|
||||
@@ -104,125 +132,277 @@ pub fn with_bound<F>(item: &Item,
|
||||
return;
|
||||
}
|
||||
}
|
||||
if !path.global && path.segments.len() == 1 {
|
||||
let id = path.segments[0].ident.clone();
|
||||
if self.all_ty_params.contains(&id) {
|
||||
self.relevant_ty_params.insert(id);
|
||||
if path.leading_colon.is_none() && path.segments.len() == 1 {
|
||||
let id = &path.segments[0].ident;
|
||||
if self.all_type_params.contains(id) {
|
||||
self.relevant_type_params.insert(id.clone());
|
||||
}
|
||||
}
|
||||
visit::walk_path(self, path);
|
||||
for segment in &path.segments {
|
||||
self.visit_path_segment(segment);
|
||||
}
|
||||
}
|
||||
|
||||
// Everything below is simply traversing the syntax tree.
|
||||
|
||||
fn visit_type(&mut self, ty: &'ast syn::Type) {
|
||||
match ty {
|
||||
syn::Type::Array(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::BareFn(ty) => {
|
||||
for arg in &ty.inputs {
|
||||
self.visit_type(&arg.ty);
|
||||
}
|
||||
self.visit_return_type(&ty.output);
|
||||
}
|
||||
syn::Type::Group(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::ImplTrait(ty) => {
|
||||
for bound in &ty.bounds {
|
||||
self.visit_type_param_bound(bound);
|
||||
}
|
||||
}
|
||||
syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
|
||||
syn::Type::Paren(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Path(ty) => {
|
||||
if let Some(qself) = &ty.qself {
|
||||
self.visit_type(&qself.ty);
|
||||
}
|
||||
self.visit_path(&ty.path);
|
||||
}
|
||||
syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Reference(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::Slice(ty) => self.visit_type(&ty.elem),
|
||||
syn::Type::TraitObject(ty) => {
|
||||
for bound in &ty.bounds {
|
||||
self.visit_type_param_bound(bound);
|
||||
}
|
||||
}
|
||||
syn::Type::Tuple(ty) => {
|
||||
for elem in &ty.elems {
|
||||
self.visit_type(elem);
|
||||
}
|
||||
}
|
||||
|
||||
syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg(test)]
|
||||
syn::Type::__TestExhaustive(_) => unimplemented!(),
|
||||
#[cfg(not(test))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
|
||||
self.visit_path_arguments(&segment.arguments);
|
||||
}
|
||||
|
||||
fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
|
||||
match arguments {
|
||||
syn::PathArguments::None => {}
|
||||
syn::PathArguments::AngleBracketed(arguments) => {
|
||||
for arg in &arguments.args {
|
||||
match arg {
|
||||
syn::GenericArgument::Type(arg) => self.visit_type(arg),
|
||||
syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
|
||||
syn::GenericArgument::Lifetime(_)
|
||||
| syn::GenericArgument::Constraint(_)
|
||||
| syn::GenericArgument::Const(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
syn::PathArguments::Parenthesized(arguments) => {
|
||||
for argument in &arguments.inputs {
|
||||
self.visit_type(argument);
|
||||
}
|
||||
self.visit_return_type(&arguments.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
|
||||
match return_type {
|
||||
syn::ReturnType::Default => {}
|
||||
syn::ReturnType::Type(_, output) => self.visit_type(output),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
|
||||
match bound {
|
||||
syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
|
||||
syn::TypeParamBound::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Type parameter should not be considered used by a macro path.
|
||||
//
|
||||
// struct TypeMacro<T> {
|
||||
// mac: T!(),
|
||||
// marker: PhantomData<T>,
|
||||
// }
|
||||
fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
|
||||
}
|
||||
|
||||
let all_type_params = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_type_params,
|
||||
relevant_type_params: HashSet::new(),
|
||||
associated_type_usage: Vec::new(),
|
||||
};
|
||||
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(_, fields) => {
|
||||
for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
|
||||
visitor.visit_field(field.original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let all_ty_params: HashSet<_> = generics.ty_params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.collect();
|
||||
|
||||
let relevant_tys = item.body
|
||||
.all_fields()
|
||||
.filter(|&field| filter(&field.attrs))
|
||||
.map(|field| &field.ty);
|
||||
|
||||
let mut visitor = FindTyParams {
|
||||
all_ty_params: all_ty_params,
|
||||
relevant_ty_params: HashSet::new(),
|
||||
};
|
||||
for ty in relevant_tys {
|
||||
visit::walk_ty(&mut visitor, ty);
|
||||
}
|
||||
|
||||
let new_predicates = generics.ty_params
|
||||
.iter()
|
||||
.map(|ty_param| ty_param.ident.clone())
|
||||
.filter(|id| visitor.relevant_ty_params.contains(id))
|
||||
.map(|id| {
|
||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
let relevant_type_params = visitor.relevant_type_params;
|
||||
let associated_type_usage = visitor.associated_type_usage;
|
||||
let new_predicates = generics
|
||||
.type_params()
|
||||
.map(|param| param.ident.clone())
|
||||
.filter(|id| relevant_type_params.contains(id))
|
||||
.map(|id| syn::TypePath {
|
||||
qself: None,
|
||||
path: id.into(),
|
||||
})
|
||||
.chain(associated_type_usage.into_iter().cloned())
|
||||
.map(|bounded_ty| {
|
||||
syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type parameter that is being bounded e.g. T
|
||||
bounded_ty: syn::Ty::Path(None, id.into()),
|
||||
bounded_ty: syn::Type::Path(bounded_ty),
|
||||
colon_token: <Token![:]>::default(),
|
||||
// the bound e.g. Serialize
|
||||
bounds: vec![syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None
|
||||
)],
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
})
|
||||
});
|
||||
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.extend(new_predicates);
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.extend(new_predicates);
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_self_bound(item: &Item,
|
||||
generics: &syn::Generics,
|
||||
bound: &syn::Path)
|
||||
-> syn::Generics
|
||||
{
|
||||
pub fn with_self_bound(
|
||||
cont: &Container,
|
||||
generics: &syn::Generics,
|
||||
bound: &syn::Path,
|
||||
) -> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
generics.where_clause.predicates.push(
|
||||
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||
bound_lifetimes: Vec::new(),
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(syn::WherePredicate::Type(syn::PredicateType {
|
||||
lifetimes: None,
|
||||
// the type that is being bounded e.g. MyStruct<'a, T>
|
||||
bounded_ty: type_of_item(item),
|
||||
bounded_ty: type_of_item(cont),
|
||||
colon_token: <Token![:]>::default(),
|
||||
// the bound e.g. Default
|
||||
bounds: vec![syn::TyParamBound::Trait(
|
||||
syn::PolyTraitRef {
|
||||
bound_lifetimes: Vec::new(),
|
||||
trait_ref: bound.clone(),
|
||||
},
|
||||
syn::TraitBoundModifier::None
|
||||
)],
|
||||
})
|
||||
);
|
||||
bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
|
||||
paren_token: None,
|
||||
modifier: syn::TraitBoundModifier::None,
|
||||
lifetimes: None,
|
||||
path: bound.clone(),
|
||||
})]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
}));
|
||||
generics
|
||||
}
|
||||
|
||||
pub fn with_lifetime_bound(generics: &syn::Generics,
|
||||
lifetime: &str)
|
||||
-> syn::Generics {
|
||||
let mut generics = generics.clone();
|
||||
|
||||
for lifetime_def in &mut generics.lifetimes {
|
||||
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
|
||||
}
|
||||
|
||||
for ty_param in &mut generics.ty_params {
|
||||
ty_param.bounds.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
|
||||
}
|
||||
|
||||
generics.lifetimes.push(syn::LifetimeDef {
|
||||
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
|
||||
let bound = syn::Lifetime::new(lifetime, Span::call_site());
|
||||
let def = syn::LifetimeDef {
|
||||
attrs: Vec::new(),
|
||||
lifetime: syn::Lifetime::new(lifetime),
|
||||
bounds: Vec::new(),
|
||||
});
|
||||
lifetime: bound.clone(),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
};
|
||||
|
||||
generics
|
||||
let params = Some(syn::GenericParam::Lifetime(def))
|
||||
.into_iter()
|
||||
.chain(generics.params.iter().cloned().map(|mut param| {
|
||||
match &mut param {
|
||||
syn::GenericParam::Lifetime(param) => {
|
||||
param.bounds.push(bound.clone());
|
||||
}
|
||||
syn::GenericParam::Type(param) => {
|
||||
param
|
||||
.bounds
|
||||
.push(syn::TypeParamBound::Lifetime(bound.clone()));
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
}
|
||||
param
|
||||
}))
|
||||
.collect();
|
||||
|
||||
syn::Generics {
|
||||
params,
|
||||
..generics.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn type_of_item(item: &Item) -> syn::Ty {
|
||||
syn::Ty::Path(None, syn::Path {
|
||||
global: false,
|
||||
segments: vec![
|
||||
syn::PathSegment {
|
||||
ident: item.ident.clone(),
|
||||
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
|
||||
lifetimes: item.generics
|
||||
.lifetimes
|
||||
.iter()
|
||||
.map(|def| def.lifetime.clone())
|
||||
.collect(),
|
||||
types: item.generics
|
||||
.ty_params
|
||||
.iter()
|
||||
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
|
||||
.collect(),
|
||||
bindings: Vec::new(),
|
||||
}),
|
||||
}
|
||||
]
|
||||
fn type_of_item(cont: &Container) -> syn::Type {
|
||||
syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: syn::Path {
|
||||
leading_colon: None,
|
||||
segments: vec![syn::PathSegment {
|
||||
ident: cont.ident.clone(),
|
||||
arguments: syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments {
|
||||
colon2_token: None,
|
||||
lt_token: <Token![<]>::default(),
|
||||
args: cont
|
||||
.generics
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| match param {
|
||||
syn::GenericParam::Type(param) => {
|
||||
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
|
||||
qself: None,
|
||||
path: param.ident.clone().into(),
|
||||
}))
|
||||
}
|
||||
syn::GenericParam::Lifetime(param) => {
|
||||
syn::GenericArgument::Lifetime(param.lifetime.clone())
|
||||
}
|
||||
syn::GenericParam::Const(_) => {
|
||||
panic!("Serde does not support const generics yet");
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
gt_token: <Token![>]>::default(),
|
||||
},
|
||||
),
|
||||
}]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+2541
-813
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(unused_extern_crates, 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,11 +1,13 @@
|
||||
use quote::{Tokens, ToTokens};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::token;
|
||||
|
||||
pub enum Fragment {
|
||||
/// Tokens that can be used as an expression.
|
||||
Expr(Tokens),
|
||||
Expr(TokenStream),
|
||||
/// Tokens that can be used inside a block. The surrounding curly braces are
|
||||
/// not part of these tokens.
|
||||
Block(Tokens),
|
||||
Block(TokenStream),
|
||||
}
|
||||
|
||||
macro_rules! quote_expr {
|
||||
@@ -24,13 +26,11 @@ macro_rules! quote_block {
|
||||
/// Block fragments in curly braces.
|
||||
pub struct Expr(pub Fragment);
|
||||
impl ToTokens for Expr {
|
||||
fn to_tokens(&self, out: &mut Tokens) {
|
||||
match self.0 {
|
||||
Fragment::Expr(ref expr) => expr.to_tokens(out),
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,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),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,17 +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);
|
||||
out.append(",");
|
||||
<Token![,]>::default().to_tokens(out);
|
||||
}
|
||||
Fragment::Block(ref block) => {
|
||||
out.append("{");
|
||||
block.to_tokens(out);
|
||||
out.append("}");
|
||||
Fragment::Block(block) => {
|
||||
token::Brace::default().surround(out, |out| block.to_tokens(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<TokenStream> for Fragment {
|
||||
fn as_ref(&self) -> &TokenStream {
|
||||
match self {
|
||||
Fragment::Expr(expr) => expr,
|
||||
Fragment::Block(block) => block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
//! A Serde ast, parsed from the Syn ast and ready to generate Rust code.
|
||||
|
||||
use internals::attr;
|
||||
use internals::check;
|
||||
use internals::{Ctxt, Derive};
|
||||
use syn;
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// Analogous 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 member: syn::Member,
|
||||
pub attrs: attr::Field,
|
||||
pub ty: &'a syn::Type,
|
||||
pub original: &'a syn::Field,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Style {
|
||||
/// Named fields.
|
||||
Struct,
|
||||
/// Many unnamed fields.
|
||||
Tuple,
|
||||
/// One unnamed field.
|
||||
Newtype,
|
||||
/// No fields.
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl<'a> 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(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(_) => {
|
||||
cx.error_spanned_by(item, "Serde does not support derive for unions");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let mut has_flatten = false;
|
||||
match &mut data {
|
||||
Data::Enum(variants) => {
|
||||
for variant in variants {
|
||||
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
for field in &mut variant.fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field
|
||||
.attrs
|
||||
.rename_by_rules(variant.attrs.rename_all_rules());
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Struct(_, fields) => {
|
||||
for field in fields {
|
||||
if field.attrs.flatten() {
|
||||
has_flatten = true;
|
||||
}
|
||||
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if has_flatten {
|
||||
attrs.mark_has_flatten();
|
||||
}
|
||||
|
||||
let mut item = Container {
|
||||
ident: item.ident.clone(),
|
||||
attrs,
|
||||
data,
|
||||
generics: &item.generics,
|
||||
original: 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(variants) => {
|
||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
||||
}
|
||||
Data::Struct(_, fields) => Box::new(fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_getter(&self) -> bool {
|
||||
self.all_fields().any(|f| f.attrs.getter().is_some())
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
variants: &'a Punctuated<syn::Variant, Token![,]>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Variant<'a>> {
|
||||
variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) =
|
||||
struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs,
|
||||
style,
|
||||
fields,
|
||||
original: variant,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn struct_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a syn::Fields,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match fields {
|
||||
syn::Fields::Named(fields) => (
|
||||
Style::Struct,
|
||||
fields_from_ast(cx, &fields.named, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unnamed(fields) => (
|
||||
Style::Tuple,
|
||||
fields_from_ast(cx, &fields.unnamed, attrs, container_default),
|
||||
),
|
||||
syn::Fields::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container_default: &attr::Default,
|
||||
) -> Vec<Field<'a>> {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| Field {
|
||||
member: match &field.ident {
|
||||
Some(ident) => syn::Member::Named(ident.clone()),
|
||||
None => syn::Member::Unnamed(i.into()),
|
||||
},
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container_default),
|
||||
ty: &field.ty,
|
||||
original: field,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
//! 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)]
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
use self::RenameRule::*;
|
||||
|
||||
/// 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,
|
||||
/// Rename direct children to "lowercase" style.
|
||||
LowerCase,
|
||||
/// Rename direct children to "UPPERCASE" style.
|
||||
UpperCase,
|
||||
/// Rename direct children to "PascalCase" style, as typically used for
|
||||
/// enum variants.
|
||||
PascalCase,
|
||||
/// Rename direct children to "camelCase" style.
|
||||
CamelCase,
|
||||
/// Rename direct children to "snake_case" style, as commonly used for
|
||||
/// fields.
|
||||
SnakeCase,
|
||||
/// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly
|
||||
/// used for constants.
|
||||
ScreamingSnakeCase,
|
||||
/// Rename direct children to "kebab-case" style.
|
||||
KebabCase,
|
||||
/// Rename direct children to "SCREAMING-KEBAB-CASE" style.
|
||||
ScreamingKebabCase,
|
||||
}
|
||||
|
||||
static RENAME_RULES: &[(&str, RenameRule)] = &[
|
||||
("lowercase", LowerCase),
|
||||
("UPPERCASE", UpperCase),
|
||||
("PascalCase", PascalCase),
|
||||
("camelCase", CamelCase),
|
||||
("snake_case", SnakeCase),
|
||||
("SCREAMING_SNAKE_CASE", ScreamingSnakeCase),
|
||||
("kebab-case", KebabCase),
|
||||
("SCREAMING-KEBAB-CASE", ScreamingKebabCase),
|
||||
];
|
||||
|
||||
impl RenameRule {
|
||||
pub fn from_str(rename_all_str: &str) -> Result<Self, ParseError> {
|
||||
for (name, rule) in RENAME_RULES {
|
||||
if rename_all_str == *name {
|
||||
return Ok(*rule);
|
||||
}
|
||||
}
|
||||
Err(ParseError {
|
||||
unknown: rename_all_str,
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
|
||||
pub fn apply_to_variant(&self, variant: &str) -> String {
|
||||
match *self {
|
||||
None | PascalCase => variant.to_owned(),
|
||||
LowerCase => variant.to_ascii_lowercase(),
|
||||
UpperCase => variant.to_ascii_uppercase(),
|
||||
CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..],
|
||||
SnakeCase => {
|
||||
let mut snake = String::new();
|
||||
for (i, ch) in variant.char_indices() {
|
||||
if i > 0 && ch.is_uppercase() {
|
||||
snake.push('_');
|
||||
}
|
||||
snake.push(ch.to_ascii_lowercase());
|
||||
}
|
||||
snake
|
||||
}
|
||||
ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(),
|
||||
KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase
|
||||
.apply_to_variant(variant)
|
||||
.replace('_', "-"),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(),
|
||||
UpperCase => field.to_ascii_uppercase(),
|
||||
PascalCase => {
|
||||
let mut pascal = String::new();
|
||||
let mut capitalize = true;
|
||||
for ch in field.chars() {
|
||||
if ch == '_' {
|
||||
capitalize = true;
|
||||
} else if capitalize {
|
||||
pascal.push(ch.to_ascii_uppercase());
|
||||
capitalize = false;
|
||||
} else {
|
||||
pascal.push(ch);
|
||||
}
|
||||
}
|
||||
pascal
|
||||
}
|
||||
CamelCase => {
|
||||
let pascal = PascalCase.apply_to_field(field);
|
||||
pascal[..1].to_ascii_lowercase() + &pascal[1..]
|
||||
}
|
||||
ScreamingSnakeCase => field.to_ascii_uppercase(),
|
||||
KebabCase => field.replace('_', "-"),
|
||||
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ParseError<'a> {
|
||||
unknown: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Display for ParseError<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("unknown rename rule `rename_all = ")?;
|
||||
Debug::fmt(self.unknown, f)?;
|
||||
f.write_str("`, expected one of ")?;
|
||||
for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
Debug::fmt(name, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_variants() {
|
||||
for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||
),
|
||||
(
|
||||
"VeryTasty",
|
||||
"verytasty",
|
||||
"VERYTASTY",
|
||||
"veryTasty",
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("A", "a", "A", "a", "a", "A", "a", "A"),
|
||||
("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_variant(original), original);
|
||||
assert_eq!(LowerCase.apply_to_variant(original), lower);
|
||||
assert_eq!(UpperCase.apply_to_variant(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_variant(original), original);
|
||||
assert_eq!(CamelCase.apply_to_variant(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_variant(original), snake);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_variant(original), kebab);
|
||||
assert_eq!(
|
||||
ScreamingKebabCase.apply_to_variant(original),
|
||||
screaming_kebab
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_fields() {
|
||||
for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[
|
||||
(
|
||||
"outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME",
|
||||
),
|
||||
(
|
||||
"very_tasty",
|
||||
"VERY_TASTY",
|
||||
"VeryTasty",
|
||||
"veryTasty",
|
||||
"VERY_TASTY",
|
||||
"very-tasty",
|
||||
"VERY-TASTY",
|
||||
),
|
||||
("a", "A", "A", "a", "A", "a", "A"),
|
||||
("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"),
|
||||
] {
|
||||
assert_eq!(None.apply_to_field(original), original);
|
||||
assert_eq!(UpperCase.apply_to_field(original), upper);
|
||||
assert_eq!(PascalCase.apply_to_field(original), pascal);
|
||||
assert_eq!(CamelCase.apply_to_field(original), camel);
|
||||
assert_eq!(SnakeCase.apply_to_field(original), original);
|
||||
assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming);
|
||||
assert_eq!(KebabCase.apply_to_field(original), kebab);
|
||||
assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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,28 @@
|
||||
pub mod ast;
|
||||
pub mod attr;
|
||||
|
||||
mod ctxt;
|
||||
pub use self::ctxt::Ctxt;
|
||||
|
||||
mod receiver;
|
||||
pub use self::receiver::replace_receiver;
|
||||
|
||||
mod case;
|
||||
mod check;
|
||||
mod respan;
|
||||
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,287 @@
|
||||
use internals::respan::respan;
|
||||
use proc_macro2::Span;
|
||||
use quote::ToTokens;
|
||||
use std::mem;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{
|
||||
parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro,
|
||||
Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate,
|
||||
};
|
||||
|
||||
pub fn replace_receiver(input: &mut DeriveInput) {
|
||||
let self_ty = {
|
||||
let ident = &input.ident;
|
||||
let ty_generics = input.generics.split_for_impl().1;
|
||||
parse_quote!(#ident #ty_generics)
|
||||
};
|
||||
let mut visitor = ReplaceReceiver(&self_ty);
|
||||
visitor.visit_generics_mut(&mut input.generics);
|
||||
visitor.visit_data_mut(&mut input.data);
|
||||
}
|
||||
|
||||
struct ReplaceReceiver<'a>(&'a TypePath);
|
||||
|
||||
impl ReplaceReceiver<'_> {
|
||||
fn self_ty(&self, span: Span) -> TypePath {
|
||||
let tokens = self.0.to_token_stream();
|
||||
let respanned = respan(tokens, span);
|
||||
syn::parse2(respanned).unwrap()
|
||||
}
|
||||
|
||||
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
|
||||
if path.leading_colon.is_some() || path.segments[0].ident != "Self" {
|
||||
return;
|
||||
}
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
self.self_to_expr_path(path);
|
||||
return;
|
||||
}
|
||||
|
||||
let span = path.segments[0].ident.span();
|
||||
*qself = Some(QSelf {
|
||||
lt_token: Token,
|
||||
ty: Box::new(Type::Path(self.self_ty(span))),
|
||||
position: 0,
|
||||
as_token: None,
|
||||
gt_token: Token,
|
||||
});
|
||||
|
||||
path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
|
||||
|
||||
let segments = mem::replace(&mut path.segments, Punctuated::new());
|
||||
path.segments = segments.into_pairs().skip(1).collect();
|
||||
}
|
||||
|
||||
fn self_to_expr_path(&self, path: &mut Path) {
|
||||
let self_ty = self.self_ty(path.segments[0].ident.span());
|
||||
let variant = mem::replace(path, self_ty.path);
|
||||
for segment in &mut path.segments {
|
||||
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
|
||||
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
|
||||
bracketed.colon2_token = Some(<Token![::]>::default());
|
||||
}
|
||||
}
|
||||
}
|
||||
if variant.segments.len() > 1 {
|
||||
path.segments.push_punct(<Token![::]>::default());
|
||||
path.segments.extend(variant.segments.into_pairs().skip(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReplaceReceiver<'_> {
|
||||
// `Self` -> `Receiver`
|
||||
fn visit_type_mut(&mut self, ty: &mut Type) {
|
||||
let span = if let Type::Path(node) = ty {
|
||||
if node.qself.is_none() && node.path.is_ident("Self") {
|
||||
node.path.segments[0].ident.span()
|
||||
} else {
|
||||
self.visit_type_path_mut(node);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
self.visit_type_mut_impl(ty);
|
||||
return;
|
||||
};
|
||||
*ty = self.self_ty(span).into();
|
||||
}
|
||||
|
||||
// `Self::Assoc` -> `<Receiver>::Assoc`
|
||||
fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
|
||||
if ty.qself.is_none() {
|
||||
self.self_to_qself(&mut ty.qself, &mut ty.path);
|
||||
}
|
||||
self.visit_type_path_mut_impl(ty);
|
||||
}
|
||||
|
||||
// `Self::method` -> `<Receiver>::method`
|
||||
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
|
||||
if expr.qself.is_none() {
|
||||
self.self_to_qself(&mut expr.qself, &mut expr.path);
|
||||
}
|
||||
self.visit_expr_path_mut_impl(expr);
|
||||
}
|
||||
|
||||
// Everything below is simply traversing the syntax tree.
|
||||
|
||||
fn visit_type_mut_impl(&mut self, ty: &mut Type) {
|
||||
match ty {
|
||||
Type::Array(ty) => {
|
||||
self.visit_type_mut(&mut ty.elem);
|
||||
self.visit_expr_mut(&mut ty.len);
|
||||
}
|
||||
Type::BareFn(ty) => {
|
||||
for arg in &mut ty.inputs {
|
||||
self.visit_type_mut(&mut arg.ty);
|
||||
}
|
||||
self.visit_return_type_mut(&mut ty.output);
|
||||
}
|
||||
Type::Group(ty) => self.visit_type_mut(&mut ty.elem),
|
||||
Type::ImplTrait(ty) => {
|
||||
for bound in &mut ty.bounds {
|
||||
self.visit_type_param_bound_mut(bound);
|
||||
}
|
||||
}
|
||||
Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac),
|
||||
Type::Paren(ty) => self.visit_type_mut(&mut ty.elem),
|
||||
Type::Path(ty) => {
|
||||
if let Some(qself) = &mut ty.qself {
|
||||
self.visit_type_mut(&mut qself.ty);
|
||||
}
|
||||
self.visit_path_mut(&mut ty.path);
|
||||
}
|
||||
Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem),
|
||||
Type::Reference(ty) => self.visit_type_mut(&mut ty.elem),
|
||||
Type::Slice(ty) => self.visit_type_mut(&mut ty.elem),
|
||||
Type::TraitObject(ty) => {
|
||||
for bound in &mut ty.bounds {
|
||||
self.visit_type_param_bound_mut(bound);
|
||||
}
|
||||
}
|
||||
Type::Tuple(ty) => {
|
||||
for elem in &mut ty.elems {
|
||||
self.visit_type_mut(elem);
|
||||
}
|
||||
}
|
||||
|
||||
Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {}
|
||||
|
||||
#[cfg(test)]
|
||||
Type::__TestExhaustive(_) => unimplemented!(),
|
||||
#[cfg(not(test))]
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) {
|
||||
if let Some(qself) = &mut ty.qself {
|
||||
self.visit_type_mut(&mut qself.ty);
|
||||
}
|
||||
self.visit_path_mut(&mut ty.path);
|
||||
}
|
||||
|
||||
fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) {
|
||||
if let Some(qself) = &mut expr.qself {
|
||||
self.visit_type_mut(&mut qself.ty);
|
||||
}
|
||||
self.visit_path_mut(&mut expr.path);
|
||||
}
|
||||
|
||||
fn visit_path_mut(&mut self, path: &mut Path) {
|
||||
for segment in &mut path.segments {
|
||||
self.visit_path_arguments_mut(&mut segment.arguments);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) {
|
||||
match arguments {
|
||||
PathArguments::None => {}
|
||||
PathArguments::AngleBracketed(arguments) => {
|
||||
for arg in &mut arguments.args {
|
||||
match arg {
|
||||
GenericArgument::Type(arg) => self.visit_type_mut(arg),
|
||||
GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty),
|
||||
GenericArgument::Lifetime(_)
|
||||
| GenericArgument::Constraint(_)
|
||||
| GenericArgument::Const(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
PathArguments::Parenthesized(arguments) => {
|
||||
for argument in &mut arguments.inputs {
|
||||
self.visit_type_mut(argument);
|
||||
}
|
||||
self.visit_return_type_mut(&mut arguments.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) {
|
||||
match return_type {
|
||||
ReturnType::Default => {}
|
||||
ReturnType::Type(_, output) => self.visit_type_mut(output),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) {
|
||||
match bound {
|
||||
TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path),
|
||||
TypeParamBound::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generics_mut(&mut self, generics: &mut Generics) {
|
||||
for param in &mut generics.params {
|
||||
match param {
|
||||
GenericParam::Type(param) => {
|
||||
for bound in &mut param.bounds {
|
||||
self.visit_type_param_bound_mut(bound);
|
||||
}
|
||||
}
|
||||
GenericParam::Lifetime(_) | GenericParam::Const(_) => {}
|
||||
}
|
||||
}
|
||||
if let Some(where_clause) = &mut generics.where_clause {
|
||||
for predicate in &mut where_clause.predicates {
|
||||
match predicate {
|
||||
WherePredicate::Type(predicate) => {
|
||||
self.visit_type_mut(&mut predicate.bounded_ty);
|
||||
for bound in &mut predicate.bounds {
|
||||
self.visit_type_param_bound_mut(bound);
|
||||
}
|
||||
}
|
||||
WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_data_mut(&mut self, data: &mut Data) {
|
||||
match data {
|
||||
Data::Struct(data) => {
|
||||
for field in &mut data.fields {
|
||||
self.visit_type_mut(&mut field.ty);
|
||||
}
|
||||
}
|
||||
Data::Enum(data) => {
|
||||
for variant in &mut data.variants {
|
||||
for field in &mut variant.fields {
|
||||
self.visit_type_mut(&mut field.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Union(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr_mut(&mut self, expr: &mut Expr) {
|
||||
match expr {
|
||||
Expr::Binary(expr) => {
|
||||
self.visit_expr_mut(&mut expr.left);
|
||||
self.visit_expr_mut(&mut expr.right);
|
||||
}
|
||||
Expr::Call(expr) => {
|
||||
self.visit_expr_mut(&mut expr.func);
|
||||
for arg in &mut expr.args {
|
||||
self.visit_expr_mut(arg);
|
||||
}
|
||||
}
|
||||
Expr::Cast(expr) => {
|
||||
self.visit_expr_mut(&mut expr.expr);
|
||||
self.visit_type_mut(&mut expr.ty);
|
||||
}
|
||||
Expr::Field(expr) => self.visit_expr_mut(&mut expr.base),
|
||||
Expr::Index(expr) => {
|
||||
self.visit_expr_mut(&mut expr.expr);
|
||||
self.visit_expr_mut(&mut expr.index);
|
||||
}
|
||||
Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr),
|
||||
Expr::Path(expr) => self.visit_expr_path_mut(expr),
|
||||
Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_macro_mut(&mut self, _mac: &mut Macro) {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||
|
||||
pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream {
|
||||
stream
|
||||
.into_iter()
|
||||
.map(|token| respan_token(token, span))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn respan_token(mut token: TokenTree, span: Span) -> TokenTree {
|
||||
if let TokenTree::Group(g) = &mut token {
|
||||
*g = Group::new(g.delimiter(), respan(g.stream(), span));
|
||||
}
|
||||
token.set_span(span);
|
||||
token
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
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");
|
||||
pub const EXPECTING: Symbol = Symbol("expecting");
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
+85
-18
@@ -1,40 +1,107 @@
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
|
||||
//! This crate provides Serde's two derive macros.
|
||||
//!
|
||||
//! ```edition2018
|
||||
//! # use serde_derive::{Serialize, Deserialize};
|
||||
//! #
|
||||
//! #[derive(Serialize, Deserialize)]
|
||||
//! # struct S;
|
||||
//! #
|
||||
//! # fn main() {}
|
||||
//! ```
|
||||
//!
|
||||
//! Please refer to [https://serde.rs/derive.html] for how to set this up.
|
||||
//!
|
||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||
|
||||
// The `quote!` macro requires deep recursion.
|
||||
#![recursion_limit = "192"]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.129")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
||||
clippy::branches_sharing_code,
|
||||
clippy::cognitive_complexity,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
|
||||
clippy::collapsible_match,
|
||||
clippy::enum_variant_names,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||
clippy::manual_map,
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::too_many_arguments,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::used_underscore_binding,
|
||||
clippy::wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
)]
|
||||
// Ignored clippy_pedantic lints
|
||||
#![allow(
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::checked_conversions,
|
||||
clippy::doc_markdown,
|
||||
clippy::enum_glob_use,
|
||||
clippy::indexing_slicing,
|
||||
clippy::items_after_statements,
|
||||
clippy::let_underscore_drop,
|
||||
clippy::map_err_ignore,
|
||||
clippy::match_same_arms,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
|
||||
clippy::match_wildcard_for_single_variants,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::option_if_let_else,
|
||||
clippy::similar_names,
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::unseparated_literal_suffix,
|
||||
clippy::unused_self,
|
||||
clippy::use_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
extern crate serde_codegen_internals as internals;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
|
||||
mod internals;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::DeriveInput;
|
||||
|
||||
#[macro_use]
|
||||
mod bound;
|
||||
#[macro_use]
|
||||
mod fragment;
|
||||
|
||||
mod ser;
|
||||
mod de;
|
||||
mod dummy;
|
||||
mod pretend;
|
||||
mod ser;
|
||||
mod try;
|
||||
|
||||
#[proc_macro_derive(Serialize, attributes(serde))]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
match ser::expand_derive_serialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
let mut input = parse_macro_input!(input as DeriveInput);
|
||||
ser::expand_derive_serialize(&mut input)
|
||||
.unwrap_or_else(to_compile_errors)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Deserialize, attributes(serde))]
|
||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||
match de::expand_derive_deserialize(&input) {
|
||||
Ok(expanded) => expanded.parse().unwrap(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
let mut input = parse_macro_input!(input as DeriveInput);
|
||||
de::expand_derive_deserialize(&mut 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,199 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::format_ident;
|
||||
|
||||
use internals::ast::{Container, Data, Field, Style, Variant};
|
||||
|
||||
// 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, is_packed: bool) -> TokenStream {
|
||||
let pretend_fields = pretend_fields_used(cont, is_packed);
|
||||
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: __v0, b: __v1 }) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
// For packed structs on sufficiently new rustc, expands to:
|
||||
//
|
||||
// match None::<&T> {
|
||||
// Some(__v @ T { a: _, b: _ }) => {
|
||||
// let _ = addr_of!(__v.a);
|
||||
// let _ = addr_of!(__v.b);
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
// For packed structs on older rustc, we assume Sized and !Drop, and expand to:
|
||||
//
|
||||
// match None::<T> {
|
||||
// Some(T { a: __v0, b: __v1 }) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
// For enums, expands to the following but only including struct variants:
|
||||
//
|
||||
// match None::<&T> {
|
||||
// Some(T::A { a: __v0 }) => {}
|
||||
// Some(T::B { b: __v0 }) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
//
|
||||
fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
|
||||
match &cont.data {
|
||||
Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
|
||||
Data::Struct(Style::Struct, fields) => if is_packed {
|
||||
pretend_fields_used_struct_packed(cont, fields)
|
||||
} else {
|
||||
pretend_fields_used_struct(cont, fields)
|
||||
},
|
||||
Data::Struct(_, _) => quote!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream {
|
||||
let type_ident = &cont.ident;
|
||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||
|
||||
let members = fields.iter().map(|field| &field.member);
|
||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream {
|
||||
let type_ident = &cont.ident;
|
||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||
|
||||
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
|
||||
|
||||
#[cfg(ptr_addr_of)]
|
||||
{
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
|
||||
#(
|
||||
let _ = _serde::__private::ptr::addr_of!(__v.#members);
|
||||
)*
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(ptr_addr_of))]
|
||||
{
|
||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||
|
||||
quote! {
|
||||
match _serde::__private::None::<#type_ident #ty_generics> {
|
||||
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
|
||||
let type_ident = &cont.ident;
|
||||
let (_, ty_generics, _) = cont.generics.split_for_impl();
|
||||
|
||||
let patterns = variants
|
||||
.iter()
|
||||
.filter_map(|variant| match variant.style {
|
||||
Style::Struct => {
|
||||
let variant_ident = &variant.ident;
|
||||
let members = variant.fields.iter().map(|field| &field.member);
|
||||
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
|
||||
Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
match _serde::__private::None::<&#type_ident #ty_generics> {
|
||||
#(
|
||||
_serde::__private::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| format_ident!("__v{}", i))
|
||||
.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::__private::None {
|
||||
_serde::__private::Some((#(#placeholders,)*)) => {
|
||||
let _ = #type_ident::#variant_ident #turbofish #pat;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote!(#(#cases)*)
|
||||
}
|
||||
+951
-395
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
use proc_macro2::{Punct, Spacing, TokenStream};
|
||||
|
||||
// None of our generated code requires the `From::from` error conversion
|
||||
// performed by the standard library's `try!` macro. With this simplified macro
|
||||
// we see a significant improvement in type checking and borrow checking time of
|
||||
// the generated code and a slight improvement in binary size.
|
||||
pub fn replacement() -> TokenStream {
|
||||
// Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it.
|
||||
let dollar = Punct::new('$', Spacing::Alone);
|
||||
|
||||
quote! {
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! try {
|
||||
(#dollar __expr:expr) => {
|
||||
match #dollar __expr {
|
||||
_serde::__private::Ok(__val) => __val,
|
||||
_serde::__private::Err(__err) => {
|
||||
return _serde::__private::Err(__err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.26.0" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
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.rs/serde_derive_internals"
|
||||
keywords = ["serde", "serialization"]
|
||||
include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
@@ -0,0 +1,12 @@
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
// Sometimes on Windows the git checkout does not correctly wire up the
|
||||
// symlink from serde_derive_internals/src to serde_derive/src/internals.
|
||||
// When this happens we'll just build based on relative paths within the git
|
||||
// repo.
|
||||
let mod_behind_symlink = Path::new("src/mod.rs");
|
||||
if !mod_behind_symlink.exists() {
|
||||
println!("cargo:rustc-cfg=serde_build_from_git");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")]
|
||||
#![allow(unknown_lints, bare_trait_objects)]
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
clippy::cognitive_complexity,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
|
||||
clippy::collapsible_match,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
|
||||
clippy::manual_map,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::redundant_field_names,
|
||||
clippy::result_unit_err,
|
||||
clippy::should_implement_trait,
|
||||
clippy::trivially_copy_pass_by_ref,
|
||||
clippy::wildcard_in_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
)]
|
||||
// Ignored clippy_pedantic lints
|
||||
#![allow(
|
||||
clippy::doc_markdown,
|
||||
clippy::enum_glob_use,
|
||||
clippy::items_after_statements,
|
||||
clippy::let_underscore_drop,
|
||||
clippy::match_same_arms,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984
|
||||
clippy::match_wildcard_for_single_variants,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::similar_names,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_lines,
|
||||
clippy::unused_self,
|
||||
clippy::wildcard_imports
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro2;
|
||||
extern crate quote;
|
||||
|
||||
#[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")]
|
||||
#[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")]
|
||||
mod internals;
|
||||
|
||||
pub use internals::*;
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../serde_derive/src/internals/
|
||||
+12
-8
@@ -1,18 +1,22 @@
|
||||
[package]
|
||||
name = "serde_test"
|
||||
version = "0.9.10"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
license = "MIT/Apache-2.0"
|
||||
version = "1.0.129" # remember to update html_root_url
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
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 = "0.9", path = "../serde" }
|
||||
serde = { version = "1.0.60", path = "../serde" }
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "serde-rs/serde" }
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0", path = "../serde" }
|
||||
serde_derive = { version = "1.0", path = "../serde_derive" }
|
||||
|
||||
[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,
|
||||
};
|
||||
|
||||
// #[track_caller] stabilized in Rust 1.46:
|
||||
// https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html#track_caller
|
||||
if minor >= 46 {
|
||||
println!("cargo:rustc-cfg=track_caller");
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
+198
-29
@@ -1,54 +1,223 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use de::Deserializer;
|
||||
use error::Error;
|
||||
use ser::Serializer;
|
||||
use token::Token;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub fn assert_tokens<T>(value: &T, tokens: &[Token<'static>])
|
||||
where T: Serialize + Deserialize + PartialEq + Debug
|
||||
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
/// b: u8,
|
||||
/// }
|
||||
///
|
||||
/// let s = S { a: 0, b: 0 };
|
||||
/// assert_tokens(&s, &[
|
||||
/// Token::Struct { name: "S", len: 2 },
|
||||
/// Token::Str("a"),
|
||||
/// Token::U8(0),
|
||||
/// Token::Str("b"),
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Serialize + Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
assert_ser_tokens(value, tokens);
|
||||
assert_de_tokens(value, tokens);
|
||||
}
|
||||
|
||||
/// Asserts that `value` serializes to the given `tokens`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_ser_tokens, Token};
|
||||
/// #
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
/// b: u8,
|
||||
/// }
|
||||
///
|
||||
/// let s = S { a: 0, b: 0 };
|
||||
/// assert_ser_tokens(&s, &[
|
||||
/// Token::Struct { name: "S", len: 2 },
|
||||
/// Token::Str("a"),
|
||||
/// Token::U8(0),
|
||||
/// Token::Str("b"),
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new(tokens.iter());
|
||||
assert_eq!(Serialize::serialize(value, &mut ser), Ok(()));
|
||||
assert_eq!(ser.next_token(), None);
|
||||
let mut ser = Serializer::new(tokens);
|
||||
match value.serialize(&mut ser) {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!("value failed to serialize: {}", err),
|
||||
}
|
||||
|
||||
if ser.remaining() > 0 {
|
||||
panic!("{} remaining tokens", ser.remaining());
|
||||
}
|
||||
}
|
||||
|
||||
/// Expect an error serializing `T`.
|
||||
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: Error)
|
||||
where T: Serialize + PartialEq + Debug
|
||||
/// Asserts that `value` serializes to the given `tokens`, and then yields
|
||||
/// `error`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// use std::sync::{Arc, Mutex};
|
||||
/// use std::thread;
|
||||
///
|
||||
/// use serde::Serialize;
|
||||
/// use serde_test::{assert_ser_tokens_error, Token};
|
||||
///
|
||||
/// #[derive(Serialize)]
|
||||
/// struct Example {
|
||||
/// lock: Arc<Mutex<u32>>,
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let example = Example { lock: Arc::new(Mutex::new(0)) };
|
||||
/// let lock = example.lock.clone();
|
||||
///
|
||||
/// let _ = thread::spawn(move || {
|
||||
/// // This thread will acquire the mutex first, unwrapping the result
|
||||
/// // of `lock` because the lock has not been poisoned.
|
||||
/// let _guard = lock.lock().unwrap();
|
||||
///
|
||||
/// // This panic while holding the lock (`_guard` is in scope) will
|
||||
/// // poison the mutex.
|
||||
/// panic!()
|
||||
/// }).join();
|
||||
///
|
||||
/// let expected = &[
|
||||
/// Token::Struct { name: "Example", len: 1 },
|
||||
/// Token::Str("lock"),
|
||||
/// ];
|
||||
/// let error = "lock poison error while serializing";
|
||||
/// assert_ser_tokens_error(&example, expected, error);
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_ser_tokens_error<T>(value: &T, tokens: &[Token], error: &str)
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let mut ser = Serializer::new(tokens.iter());
|
||||
let v: Result<(), Error> = Serialize::serialize(value, &mut ser);
|
||||
assert_eq!(v.as_ref(), Err(&error));
|
||||
assert_eq!(ser.next_token(), None);
|
||||
let mut ser = Serializer::new(tokens);
|
||||
match value.serialize(&mut ser) {
|
||||
Ok(_) => panic!("value serialized successfully"),
|
||||
Err(e) => assert_eq!(e, *error),
|
||||
}
|
||||
|
||||
if ser.remaining() > 0 {
|
||||
panic!("{} remaining tokens", ser.remaining());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_de_tokens<T>(value: &T, tokens: &[Token<'static>])
|
||||
where T: Deserialize + PartialEq + Debug
|
||||
/// Asserts that the given `tokens` deserialize into `value`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_de_tokens, Token};
|
||||
/// #
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
/// b: u8,
|
||||
/// }
|
||||
///
|
||||
/// let s = S { a: 0, b: 0 };
|
||||
/// assert_de_tokens(&s, &[
|
||||
/// Token::Struct { name: "S", len: 2 },
|
||||
/// Token::Str("a"),
|
||||
/// Token::U8(0),
|
||||
/// Token::Str("b"),
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
|
||||
where
|
||||
T: Deserialize<'de> + PartialEq + Debug,
|
||||
{
|
||||
let mut de = Deserializer::new(tokens.to_vec().into_iter());
|
||||
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
|
||||
assert_eq!(v.as_ref(), Ok(value));
|
||||
assert_eq!(de.next_token(), None);
|
||||
let mut de = Deserializer::new(tokens);
|
||||
let mut deserialized_val = match T::deserialize(&mut de) {
|
||||
Ok(v) => {
|
||||
assert_eq!(v, *value);
|
||||
v
|
||||
}
|
||||
Err(e) => panic!("tokens failed to deserialize: {}", e),
|
||||
};
|
||||
if de.remaining() > 0 {
|
||||
panic!("{} remaining tokens", de.remaining());
|
||||
}
|
||||
|
||||
// Do the same thing for deserialize_in_place. This isn't *great* because a
|
||||
// no-op impl of deserialize_in_place can technically succeed here. Still,
|
||||
// this should catch a lot of junk.
|
||||
let mut de = Deserializer::new(tokens);
|
||||
match T::deserialize_in_place(&mut de, &mut deserialized_val) {
|
||||
Ok(()) => {
|
||||
assert_eq!(deserialized_val, *value);
|
||||
}
|
||||
Err(e) => panic!("tokens failed to deserialize_in_place: {}", e),
|
||||
}
|
||||
if de.remaining() > 0 {
|
||||
panic!("{} remaining tokens", de.remaining());
|
||||
}
|
||||
}
|
||||
|
||||
/// Expect an error deserializing tokens into a `T`.
|
||||
pub fn assert_de_tokens_error<T>(tokens: &[Token<'static>], error: Error)
|
||||
where T: Deserialize + PartialEq + Debug
|
||||
/// Asserts that the given `tokens` yield `error` when deserializing.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_de_tokens_error, Token};
|
||||
/// #
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// #[serde(deny_unknown_fields)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
/// b: u8,
|
||||
/// }
|
||||
///
|
||||
/// assert_de_tokens_error::<S>(
|
||||
/// &[
|
||||
/// Token::Struct { name: "S", len: 2 },
|
||||
/// Token::Str("x"),
|
||||
/// ],
|
||||
/// "unknown field `x`, expected `a` or `b`",
|
||||
/// );
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
pub fn assert_de_tokens_error<'de, T>(tokens: &'de [Token], error: &str)
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
let mut de = Deserializer::new(tokens.to_vec().into_iter());
|
||||
let v: Result<T, Error> = Deserialize::deserialize(&mut de);
|
||||
assert_eq!(v, Err(error));
|
||||
let mut de = Deserializer::new(tokens);
|
||||
match T::deserialize(&mut de) {
|
||||
Ok(_) => panic!("tokens deserialized successfully"),
|
||||
Err(e) => assert_eq!(e, *error),
|
||||
}
|
||||
|
||||
// There may be one token left if a peek caused the error
|
||||
de.next_token();
|
||||
assert_eq!(de.next_token(), None);
|
||||
de.next_token_opt();
|
||||
|
||||
if de.remaining() > 0 {
|
||||
panic!("{} remaining tokens", de.remaining());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,847 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde::ser::{
|
||||
SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
|
||||
SerializeTupleStruct, SerializeTupleVariant,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Readable<T: ?Sized>(T);
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Compact<T: ?Sized>(T);
|
||||
|
||||
/// Trait to determine whether a value is represented in human-readable or
|
||||
/// compact form.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
/// use serde_test::{assert_tokens, Configure, Token};
|
||||
///
|
||||
/// #[derive(Debug, PartialEq)]
|
||||
/// struct Example(u8, u8);
|
||||
///
|
||||
/// impl Serialize for Example {
|
||||
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
/// where
|
||||
/// S: Serializer,
|
||||
/// {
|
||||
/// if serializer.is_human_readable() {
|
||||
/// format!("{}.{}", self.0, self.1).serialize(serializer)
|
||||
/// } else {
|
||||
/// (self.0, self.1).serialize(serializer)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'de> Deserialize<'de> for Example {
|
||||
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
/// where
|
||||
/// D: Deserializer<'de>,
|
||||
/// {
|
||||
/// use serde::de::Error;
|
||||
/// if deserializer.is_human_readable() {
|
||||
/// let s = String::deserialize(deserializer)?;
|
||||
/// let parts: Vec<_> = s.split('.').collect();
|
||||
/// Ok(Example(
|
||||
/// parts[0].parse().map_err(D::Error::custom)?,
|
||||
/// parts[1].parse().map_err(D::Error::custom)?,
|
||||
/// ))
|
||||
/// } else {
|
||||
/// let (x, y) = Deserialize::deserialize(deserializer)?;
|
||||
/// Ok(Example(x, y))
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// assert_tokens(
|
||||
/// &Example(1, 0).compact(),
|
||||
/// &[
|
||||
/// Token::Tuple { len: 2 },
|
||||
/// Token::U8(1),
|
||||
/// Token::U8(0),
|
||||
/// Token::TupleEnd,
|
||||
/// ],
|
||||
/// );
|
||||
/// assert_tokens(&Example(1, 0).readable(), &[Token::Str("1.0")]);
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Configure {
|
||||
/// Marks `self` as using `is_human_readable == true`
|
||||
fn readable(self) -> Readable<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Readable(self)
|
||||
}
|
||||
/// Marks `self` as using `is_human_readable == false`
|
||||
fn compact(self) -> Compact<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Compact(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Configure for T {}
|
||||
|
||||
impl<T: ?Sized> Serialize for Readable<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(Readable(serializer))
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> Serialize for Compact<T>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.0.serialize(Compact(serializer))
|
||||
}
|
||||
}
|
||||
impl<'de, T> Deserialize<'de> for Readable<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(Readable(deserializer)).map(Readable)
|
||||
}
|
||||
}
|
||||
impl<'de, T> Deserialize<'de> for Compact<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
T::deserialize(Compact(deserializer)).map(Compact)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> DeserializeSeed<'de> for Readable<T>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
type Value = T::Value;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
self.0.deserialize(Readable(deserializer))
|
||||
}
|
||||
}
|
||||
impl<'de, T> DeserializeSeed<'de> for Compact<T>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
type Value = T::Value;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
self.0.deserialize(Compact(deserializer))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_method {
|
||||
($name: ident (self $(, $arg: ident : $arg_type: ty)* ) -> $return_type: ty) => {
|
||||
fn $name (self $(, $arg : $arg_type)* ) -> $return_type {
|
||||
(self.0).$name( $($arg),* )
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_serialize_methods {
|
||||
( $( $name: ident $arg_type: ty ),* ) => {
|
||||
$(
|
||||
forward_method!($name(self, v : $arg_type) -> Result<Self::Ok, Self::Error>);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_serializer {
|
||||
($wrapper:ident, $is_human_readable:expr) => {
|
||||
impl<S> Serializer for $wrapper<S>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
|
||||
type SerializeSeq = $wrapper<S::SerializeSeq>;
|
||||
type SerializeTuple = $wrapper<S::SerializeTuple>;
|
||||
type SerializeTupleStruct = $wrapper<S::SerializeTupleStruct>;
|
||||
type SerializeTupleVariant = $wrapper<S::SerializeTupleVariant>;
|
||||
type SerializeMap = $wrapper<S::SerializeMap>;
|
||||
type SerializeStruct = $wrapper<S::SerializeStruct>;
|
||||
type SerializeStructVariant = $wrapper<S::SerializeStructVariant>;
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
$is_human_readable
|
||||
}
|
||||
|
||||
forward_serialize_methods! {
|
||||
serialize_bool bool,
|
||||
serialize_i8 i8,
|
||||
serialize_i16 i16,
|
||||
serialize_i32 i32,
|
||||
serialize_i64 i64,
|
||||
serialize_u8 u8,
|
||||
serialize_u16 u16,
|
||||
serialize_u32 u32,
|
||||
serialize_u64 u64,
|
||||
serialize_f32 f32,
|
||||
serialize_f64 f64,
|
||||
serialize_char char,
|
||||
serialize_str &str,
|
||||
serialize_bytes &[u8],
|
||||
serialize_unit_struct &'static str
|
||||
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.serialize_unit()
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
self.0.serialize_unit_variant(name, variant_index, variant)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_newtype_struct(name, &$wrapper(value))
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0
|
||||
.serialize_newtype_variant(name, variant_index, variant, &$wrapper(value))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<S::Ok, Self::Error> {
|
||||
self.0.serialize_none()
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<S::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_some(&$wrapper(value))
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
self.0.serialize_seq(len).map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
self.0.serialize_tuple(len).map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
self.0.serialize_tuple_struct(name, len).map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
self.0
|
||||
.serialize_tuple_variant(name, variant_index, variant, len)
|
||||
.map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
self.0.serialize_map(len).map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
self.0.serialize_struct(name, len).map($wrapper)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
variant_index: u32,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
self.0
|
||||
.serialize_struct_variant(name, variant_index, variant, len)
|
||||
.map($wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeSeq for $wrapper<S>
|
||||
where
|
||||
S: SerializeSeq,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_element(&$wrapper(value))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeTuple for $wrapper<S>
|
||||
where
|
||||
S: SerializeTuple,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_element(&$wrapper(value))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeTupleStruct for $wrapper<S>
|
||||
where
|
||||
S: SerializeTupleStruct,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_field(&$wrapper(value))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeTupleVariant for $wrapper<S>
|
||||
where
|
||||
S: SerializeTupleVariant,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_field(&$wrapper(value))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeMap for $wrapper<S>
|
||||
where
|
||||
S: SerializeMap,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_key(&$wrapper(key))
|
||||
}
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_value(&$wrapper(value))
|
||||
}
|
||||
fn serialize_entry<K: ?Sized, V: ?Sized>(
|
||||
&mut self,
|
||||
key: &K,
|
||||
value: &V,
|
||||
) -> Result<(), S::Error>
|
||||
where
|
||||
K: Serialize,
|
||||
V: Serialize,
|
||||
{
|
||||
self.0.serialize_entry(key, &$wrapper(value))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeStruct for $wrapper<S>
|
||||
where
|
||||
S: SerializeStruct,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
field: &T,
|
||||
) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_field(name, &$wrapper(field))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> SerializeStructVariant for $wrapper<S>
|
||||
where
|
||||
S: SerializeStructVariant,
|
||||
{
|
||||
type Ok = S::Ok;
|
||||
type Error = S::Error;
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
field: &T,
|
||||
) -> Result<(), S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.0.serialize_field(name, &$wrapper(field))
|
||||
}
|
||||
fn end(self) -> Result<S::Ok, S::Error> {
|
||||
self.0.end()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_serializer!(Readable, true);
|
||||
impl_serializer!(Compact, false);
|
||||
|
||||
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
|
||||
|
||||
macro_rules! forward_deserialize_methods {
|
||||
( $wrapper : ident ( $( $name: ident ),* ) ) => {
|
||||
$(
|
||||
fn $name<V>(self, visitor: V) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
(self.0).$name($wrapper(visitor))
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_deserializer {
|
||||
($wrapper:ident, $is_human_readable:expr) => {
|
||||
impl<'de, D> Deserializer<'de> for $wrapper<D>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
type Error = D::Error;
|
||||
|
||||
forward_deserialize_methods! {
|
||||
$wrapper (
|
||||
deserialize_any,
|
||||
deserialize_bool,
|
||||
deserialize_u8,
|
||||
deserialize_u16,
|
||||
deserialize_u32,
|
||||
deserialize_u64,
|
||||
deserialize_i8,
|
||||
deserialize_i16,
|
||||
deserialize_i32,
|
||||
deserialize_i64,
|
||||
deserialize_f32,
|
||||
deserialize_f64,
|
||||
deserialize_char,
|
||||
deserialize_str,
|
||||
deserialize_string,
|
||||
deserialize_bytes,
|
||||
deserialize_byte_buf,
|
||||
deserialize_option,
|
||||
deserialize_unit,
|
||||
deserialize_seq,
|
||||
deserialize_map,
|
||||
deserialize_identifier,
|
||||
deserialize_ignored_any
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.deserialize_unit_struct(name, $wrapper(visitor))
|
||||
}
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.deserialize_newtype_struct(name, $wrapper(visitor))
|
||||
}
|
||||
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.deserialize_tuple(len, $wrapper(visitor))
|
||||
}
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0
|
||||
.deserialize_tuple_struct(name, len, $wrapper(visitor))
|
||||
}
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.deserialize_struct(name, fields, $wrapper(visitor))
|
||||
}
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.deserialize_enum(name, variants, $wrapper(visitor))
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
$is_human_readable
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, D> Visitor<'de> for $wrapper<D>
|
||||
where
|
||||
D: Visitor<'de>,
|
||||
{
|
||||
type Value = D::Value;
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.0.expecting(formatter)
|
||||
}
|
||||
fn visit_bool<E>(self, v: bool) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_bool(v)
|
||||
}
|
||||
fn visit_i8<E>(self, v: i8) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_i8(v)
|
||||
}
|
||||
fn visit_i16<E>(self, v: i16) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_i16(v)
|
||||
}
|
||||
fn visit_i32<E>(self, v: i32) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_i32(v)
|
||||
}
|
||||
fn visit_i64<E>(self, v: i64) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_i64(v)
|
||||
}
|
||||
fn visit_u8<E>(self, v: u8) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_u8(v)
|
||||
}
|
||||
fn visit_u16<E>(self, v: u16) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_u16(v)
|
||||
}
|
||||
fn visit_u32<E>(self, v: u32) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_u32(v)
|
||||
}
|
||||
fn visit_u64<E>(self, v: u64) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_u64(v)
|
||||
}
|
||||
fn visit_f32<E>(self, v: f32) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_f32(v)
|
||||
}
|
||||
fn visit_f64<E>(self, v: f64) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_f64(v)
|
||||
}
|
||||
fn visit_char<E>(self, v: char) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_char(v)
|
||||
}
|
||||
fn visit_str<E>(self, v: &str) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_str(v)
|
||||
}
|
||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_borrowed_str(v)
|
||||
}
|
||||
fn visit_string<E>(self, v: String) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_string(v)
|
||||
}
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_bytes(v)
|
||||
}
|
||||
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_borrowed_bytes(v)
|
||||
}
|
||||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_byte_buf(v)
|
||||
}
|
||||
fn visit_none<E>(self) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_none()
|
||||
}
|
||||
fn visit_some<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
|
||||
where
|
||||
D2: Deserializer<'de>,
|
||||
{
|
||||
self.0.visit_some($wrapper(deserializer))
|
||||
}
|
||||
fn visit_unit<E>(self) -> Result<D::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.0.visit_unit()
|
||||
}
|
||||
fn visit_newtype_struct<D2>(self, deserializer: D2) -> Result<Self::Value, D2::Error>
|
||||
where
|
||||
D2: Deserializer<'de>,
|
||||
{
|
||||
self.0.visit_newtype_struct($wrapper(deserializer))
|
||||
}
|
||||
fn visit_seq<V>(self, seq: V) -> Result<D::Value, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
self.0.visit_seq($wrapper(seq))
|
||||
}
|
||||
fn visit_map<V>(self, map: V) -> Result<D::Value, V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
self.0.visit_map($wrapper(map))
|
||||
}
|
||||
fn visit_enum<V>(self, data: V) -> Result<D::Value, V::Error>
|
||||
where
|
||||
V: EnumAccess<'de>,
|
||||
{
|
||||
self.0.visit_enum($wrapper(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, D> SeqAccess<'de> for $wrapper<D>
|
||||
where
|
||||
D: SeqAccess<'de>,
|
||||
{
|
||||
type Error = D::Error;
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, D::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.next_element_seed($wrapper(seed))
|
||||
}
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, D> MapAccess<'de> for $wrapper<D>
|
||||
where
|
||||
D: MapAccess<'de>,
|
||||
{
|
||||
type Error = D::Error;
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, D::Error>
|
||||
where
|
||||
K: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.next_key_seed($wrapper(seed))
|
||||
}
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.next_value_seed($wrapper(seed))
|
||||
}
|
||||
fn next_entry_seed<K, V>(
|
||||
&mut self,
|
||||
kseed: K,
|
||||
vseed: V,
|
||||
) -> Result<Option<(K::Value, V::Value)>, D::Error>
|
||||
where
|
||||
K: DeserializeSeed<'de>,
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.next_entry_seed($wrapper(kseed), $wrapper(vseed))
|
||||
}
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, D> EnumAccess<'de> for $wrapper<D>
|
||||
where
|
||||
D: EnumAccess<'de>,
|
||||
{
|
||||
type Error = D::Error;
|
||||
type Variant = $wrapper<D::Variant>;
|
||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0
|
||||
.variant_seed($wrapper(seed))
|
||||
.map(|(value, variant)| (value, $wrapper(variant)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, D> VariantAccess<'de> for $wrapper<D>
|
||||
where
|
||||
D: VariantAccess<'de>,
|
||||
{
|
||||
type Error = D::Error;
|
||||
fn unit_variant(self) -> Result<(), D::Error> {
|
||||
self.0.unit_variant()
|
||||
}
|
||||
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, D::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
self.0.newtype_variant_seed($wrapper(seed))
|
||||
}
|
||||
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.tuple_variant(len, $wrapper(visitor))
|
||||
}
|
||||
fn struct_variant<V>(
|
||||
self,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, D::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.0.struct_variant(fields, $wrapper(visitor))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_deserializer!(Readable, true);
|
||||
impl_deserializer!(Compact, false);
|
||||
+459
-395
File diff suppressed because it is too large
Load Diff
+20
-25
@@ -1,48 +1,43 @@
|
||||
use std::error;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use serde::{ser, de};
|
||||
use serde::{de, ser};
|
||||
|
||||
use token::Token;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Error {
|
||||
Message(String),
|
||||
InvalidName(&'static str),
|
||||
UnexpectedToken(Token<'static>),
|
||||
EndOfTokens,
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Error {
|
||||
msg: String,
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Error {
|
||||
Error::Message(msg.to_string())
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error {
|
||||
msg: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl de::Error for Error {
|
||||
fn custom<T: Display>(msg: T) -> Error {
|
||||
Error::Message(msg.to_string())
|
||||
fn custom<T: Display>(msg: T) -> Self {
|
||||
Error {
|
||||
msg: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::Message(ref msg) => formatter.write_str(msg),
|
||||
Error::InvalidName(name) => write!(formatter, "invalid name `{}`", name),
|
||||
Error::UnexpectedToken(_) => formatter.write_str("unexpected token"),
|
||||
Error::EndOfTokens => formatter.write_str("end of tokens"),
|
||||
}
|
||||
formatter.write_str(&self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Message(ref msg) => msg,
|
||||
Error::InvalidName(_) => "invalid name",
|
||||
Error::UnexpectedToken(_) => "unexpected token",
|
||||
Error::EndOfTokens => "end of tokens",
|
||||
}
|
||||
&self.msg
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Error {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.msg == other
|
||||
}
|
||||
}
|
||||
|
||||
+182
-10
@@ -1,18 +1,190 @@
|
||||
//! This crate provides a convenient concise way to write unit tests for
|
||||
//! implementations of [`Serialize`] and [`Deserialize`].
|
||||
//!
|
||||
//! [`Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
|
||||
//! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
|
||||
//!
|
||||
//! The `Serialize` impl for a value can be characterized by the sequence of
|
||||
//! [`Serializer`] calls that are made in the course of serializing the value,
|
||||
//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly
|
||||
//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to
|
||||
//! test that a value serializes to a particular sequence of method calls, an
|
||||
//! [`assert_de_tokens`] function to test that a value can be deserialized from
|
||||
//! a particular sequence of method calls, and an [`assert_tokens`] function to
|
||||
//! test both directions. There are also functions to test expected failure
|
||||
//! conditions.
|
||||
//!
|
||||
//! [`Serializer`]: https://docs.serde.rs/serde/ser/trait.Serializer.html
|
||||
//! [`Token`]: https://docs.serde.rs/serde_test/enum.Token.html
|
||||
//! [`assert_ser_tokens`]: https://docs.serde.rs/serde_test/fn.assert_ser_tokens.html
|
||||
//! [`assert_de_tokens`]: https://docs.serde.rs/serde_test/fn.assert_de_tokens.html
|
||||
//! [`assert_tokens`]: https://docs.serde.rs/serde_test/fn.assert_tokens.html
|
||||
//!
|
||||
//! Here is an example from the [`linked-hash-map`] crate.
|
||||
//!
|
||||
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
|
||||
//!
|
||||
//! ```edition2018
|
||||
//! # const IGNORE: &str = stringify! {
|
||||
//! use linked_hash_map::LinkedHashMap;
|
||||
//! # };
|
||||
//! use serde_test::{Token, assert_tokens};
|
||||
//!
|
||||
//! # use std::fmt;
|
||||
//! # use std::marker::PhantomData;
|
||||
//! #
|
||||
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
|
||||
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
|
||||
//! #
|
||||
//! # // Dumb imitation of LinkedHashMap.
|
||||
//! # #[derive(PartialEq, Debug)]
|
||||
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
|
||||
//! #
|
||||
//! # impl<K, V> LinkedHashMap<K, V> {
|
||||
//! # fn new() -> Self {
|
||||
//! # LinkedHashMap(Vec::new())
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn insert(&mut self, k: K, v: V) {
|
||||
//! # self.0.push((k, v));
|
||||
//! # }
|
||||
//! # }
|
||||
//! #
|
||||
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
|
||||
//! # where
|
||||
//! # K: Serialize,
|
||||
//! # V: Serialize,
|
||||
//! # {
|
||||
//! # fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
//! # where
|
||||
//! # S: Serializer,
|
||||
//! # {
|
||||
//! # let mut map = serializer.serialize_map(Some(self.0.len()))?;
|
||||
//! # for &(ref k, ref v) in &self.0 {
|
||||
//! # map.serialize_entry(k, v)?;
|
||||
//! # }
|
||||
//! # map.end()
|
||||
//! # }
|
||||
//! # }
|
||||
//! #
|
||||
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
|
||||
//! #
|
||||
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
|
||||
//! # where
|
||||
//! # K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>,
|
||||
//! # {
|
||||
//! # type Value = LinkedHashMap<K, V>;
|
||||
//! #
|
||||
//! # fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
|
||||
//! # where
|
||||
//! # M: MapAccess<'de>,
|
||||
//! # {
|
||||
//! # let mut map = LinkedHashMap::new();
|
||||
//! # while let Some((key, value)) = access.next_entry()? {
|
||||
//! # map.insert(key, value);
|
||||
//! # }
|
||||
//! # Ok(map)
|
||||
//! # }
|
||||
//! # }
|
||||
//! #
|
||||
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
|
||||
//! # where
|
||||
//! # K: Deserialize<'de>,
|
||||
//! # V: Deserialize<'de>,
|
||||
//! # {
|
||||
//! # fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
//! # where
|
||||
//! # D: Deserializer<'de>,
|
||||
//! # {
|
||||
//! # deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
|
||||
//! # }
|
||||
//! # }
|
||||
//! #
|
||||
//! #[test]
|
||||
//! # fn not_a_test_ser_de_empty() {}
|
||||
//! fn test_ser_de_empty() {
|
||||
//! let map = LinkedHashMap::<char, u32>::new();
|
||||
//!
|
||||
//! assert_tokens(&map, &[
|
||||
//! Token::Map { len: Some(0) },
|
||||
//! Token::MapEnd,
|
||||
//! ]);
|
||||
//! }
|
||||
//!
|
||||
//! #[test]
|
||||
//! # fn not_a_test_ser_de() {}
|
||||
//! fn test_ser_de() {
|
||||
//! let mut map = LinkedHashMap::new();
|
||||
//! map.insert('b', 20);
|
||||
//! map.insert('a', 10);
|
||||
//! map.insert('c', 30);
|
||||
//!
|
||||
//! assert_tokens(&map, &[
|
||||
//! Token::Map { len: Some(3) },
|
||||
//! Token::Char('b'),
|
||||
//! Token::I32(20),
|
||||
//!
|
||||
//! Token::Char('a'),
|
||||
//! Token::I32(10),
|
||||
//!
|
||||
//! Token::Char('c'),
|
||||
//! Token::I32(30),
|
||||
//! Token::MapEnd,
|
||||
//! ]);
|
||||
//! }
|
||||
//! #
|
||||
//! # fn main() {
|
||||
//! # test_ser_de_empty();
|
||||
//! # test_ser_de();
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.129")]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
|
||||
// Ignored clippy lints
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
|
||||
// Ignored clippy_pedantic lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
cloned_instead_of_copied,
|
||||
empty_line_after_outer_attr,
|
||||
missing_docs_in_private_items,
|
||||
missing_panics_doc,
|
||||
module_name_repetitions,
|
||||
must_use_candidate,
|
||||
redundant_field_names,
|
||||
too_many_lines,
|
||||
use_debug,
|
||||
use_self
|
||||
)
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod assert;
|
||||
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error, assert_de_tokens,
|
||||
assert_de_tokens_error};
|
||||
|
||||
mod ser;
|
||||
pub use ser::Serializer;
|
||||
|
||||
mod de;
|
||||
pub use de::Deserializer;
|
||||
mod error;
|
||||
mod ser;
|
||||
|
||||
mod assert;
|
||||
mod configure;
|
||||
mod token;
|
||||
|
||||
pub use assert::{
|
||||
assert_de_tokens, assert_de_tokens_error, assert_ser_tokens, assert_ser_tokens_error,
|
||||
assert_tokens,
|
||||
};
|
||||
pub use token::Token;
|
||||
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
pub use configure::{Compact, Configure, Readable};
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
pub use de::Deserializer;
|
||||
|
||||
+244
-143
@@ -1,363 +1,464 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use serde::{ser, Serialize};
|
||||
|
||||
use error::Error;
|
||||
use token::Token;
|
||||
|
||||
pub struct Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
tokens: I,
|
||||
phantom: PhantomData<&'a Token<'a>>,
|
||||
/// A `Serializer` that ensures that a value serializes to a given list of
|
||||
/// tokens.
|
||||
#[derive(Debug)]
|
||||
pub struct Serializer<'a> {
|
||||
tokens: &'a [Token],
|
||||
}
|
||||
|
||||
impl<'a, I> Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
pub fn new(tokens: I) -> Serializer<'a, I> {
|
||||
Serializer {
|
||||
tokens: tokens,
|
||||
phantom: PhantomData,
|
||||
impl<'a> Serializer<'a> {
|
||||
/// Creates the serializer.
|
||||
pub fn new(tokens: &'a [Token]) -> Self {
|
||||
Serializer { tokens: tokens }
|
||||
}
|
||||
|
||||
/// Pulls the next token off of the serializer, ignoring it.
|
||||
fn next_token(&mut self) -> Option<Token> {
|
||||
if let Some((&first, rest)) = self.tokens.split_first() {
|
||||
self.tokens = rest;
|
||||
Some(first)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_token(&mut self) -> Option<&'a Token<'a>> {
|
||||
self.tokens.next()
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.tokens.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::Serializer for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
macro_rules! assert_next_token {
|
||||
($ser:expr, $actual:ident) => {{
|
||||
assert_next_token!($ser, stringify!($actual), Token::$actual, true);
|
||||
}};
|
||||
($ser:expr, $actual:ident($v:expr)) => {{
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!(concat!(stringify!($actual), "({:?})"), $v),
|
||||
Token::$actual(v),
|
||||
v == $v
|
||||
);
|
||||
}};
|
||||
($ser:expr, $actual:ident { $($k:ident),* }) => {{
|
||||
let compare = ($($k,)*);
|
||||
let field_format = || {
|
||||
use std::fmt::Write;
|
||||
let mut buffer = String::new();
|
||||
$(
|
||||
write!(&mut buffer, concat!(stringify!($k), ": {:?}, "), $k).unwrap();
|
||||
)*
|
||||
buffer
|
||||
};
|
||||
assert_next_token!(
|
||||
$ser,
|
||||
format_args!(concat!(stringify!($actual), " {{ {}}}"), field_format()),
|
||||
Token::$actual { $($k),* },
|
||||
($($k,)*) == compare
|
||||
);
|
||||
}};
|
||||
($ser:expr, $actual:expr, $pat:pat, $guard:expr) => {
|
||||
match $ser.next_token() {
|
||||
Some($pat) if $guard => {}
|
||||
Some(expected) => {
|
||||
panic!("expected Token::{} but serialized as {}",
|
||||
expected, $actual);
|
||||
}
|
||||
None => {
|
||||
panic!("expected end of tokens, but {} was serialized",
|
||||
$actual);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Self;
|
||||
type SerializeTuple = Self;
|
||||
type SerializeTupleStruct = Self;
|
||||
type SerializeTupleVariant = Self;
|
||||
type SerializeTupleVariant = Variant<'s, 'a>;
|
||||
type SerializeMap = Self;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStructVariant = Self;
|
||||
type SerializeStructVariant = Variant<'s, 'a>;
|
||||
|
||||
fn serialize_bool(self, v: bool) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Bool(v)));
|
||||
assert_next_token!(self, Bool(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I8(v)));
|
||||
assert_next_token!(self, I8(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I16(v)));
|
||||
assert_next_token!(self, I16(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I32(v)));
|
||||
assert_next_token!(self, I32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::I64(v)));
|
||||
assert_next_token!(self, I64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U8(v)));
|
||||
assert_next_token!(self, U8(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U16(v)));
|
||||
assert_next_token!(self, U16(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U32(v)));
|
||||
assert_next_token!(self, U32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::U64(v)));
|
||||
assert_next_token!(self, U64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::F32(v)));
|
||||
assert_next_token!(self, F32(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::F64(v)));
|
||||
assert_next_token!(self, F64(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Char(v)));
|
||||
assert_next_token!(self, Char(v));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Str(v)));
|
||||
match self.tokens.first() {
|
||||
Some(&Token::BorrowedStr(_)) => assert_next_token!(self, BorrowedStr(v)),
|
||||
Some(&Token::String(_)) => assert_next_token!(self, String(v)),
|
||||
_ => assert_next_token!(self, Str(v)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, value: &[u8]) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Bytes(value)));
|
||||
fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> {
|
||||
match self.tokens.first() {
|
||||
Some(&Token::BorrowedBytes(_)) => assert_next_token!(self, BorrowedBytes(v)),
|
||||
Some(&Token::ByteBuf(_)) => assert_next_token!(self, ByteBuf(v)),
|
||||
_ => assert_next_token!(self, Bytes(v)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Unit));
|
||||
assert_next_token!(self, Unit);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, name: &str) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::UnitStruct(name)));
|
||||
fn serialize_unit_struct(self, name: &'static str) -> Result<(), Error> {
|
||||
assert_next_token!(self, UnitStruct { name });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str)
|
||||
-> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumUnit(name, variant)));
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<(), Error> {
|
||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
||||
self.next_token();
|
||||
assert_next_token!(self, Str(variant));
|
||||
assert_next_token!(self, Unit);
|
||||
} else {
|
||||
assert_next_token!(self, UnitVariant { name, variant });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructNewType(name)));
|
||||
assert_next_token!(self, NewtypeStruct { name });
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized>(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
value: &T)
|
||||
-> Result<(), Error>
|
||||
where T: Serialize
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant)));
|
||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
||||
self.next_token();
|
||||
assert_next_token!(self, Str(variant));
|
||||
} else {
|
||||
assert_next_token!(self, NewtypeVariant { name, variant });
|
||||
}
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Option(false)));
|
||||
assert_next_token!(self, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::Option(true)));
|
||||
assert_next_token!(self, Some);
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqStart(len)));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_seq_fixed_size(self, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqArrayStart(len)));
|
||||
assert_next_token!(self, Seq { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStart(len)));
|
||||
assert_next_token!(self, Tuple { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::TupleStructStart(name, len)));
|
||||
assert_next_token!(self, TupleStruct { name, len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
len: usize)
|
||||
-> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::EnumSeqStart(name, variant, len)));
|
||||
Ok(self)
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Error> {
|
||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
||||
self.next_token();
|
||||
assert_next_token!(self, Str(variant));
|
||||
let len = Some(len);
|
||||
assert_next_token!(self, Seq { len });
|
||||
Ok(Variant {
|
||||
ser: self,
|
||||
end: Token::SeqEnd,
|
||||
})
|
||||
} else {
|
||||
assert_next_token!(self, TupleVariant { name, variant, len });
|
||||
Ok(Variant {
|
||||
ser: self,
|
||||
end: Token::TupleVariantEnd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_map(self, len: Option<usize>) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapStart(len)));
|
||||
assert_next_token!(self, Map { len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_struct(self, name: &str, len: usize) -> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len)));
|
||||
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self, Error> {
|
||||
assert_next_token!(self, Struct { name, len });
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(self,
|
||||
name: &str,
|
||||
_variant_index: usize,
|
||||
variant: &str,
|
||||
len: usize)
|
||||
-> Result<Self, Error> {
|
||||
assert_eq!(self.tokens.next(),
|
||||
Some(&Token::EnumMapStart(name, variant, len)));
|
||||
Ok(self)
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Error> {
|
||||
if self.tokens.first() == Some(&Token::Enum { name: name }) {
|
||||
self.next_token();
|
||||
assert_next_token!(self, Str(variant));
|
||||
let len = Some(len);
|
||||
assert_next_token!(self, Map { len });
|
||||
Ok(Variant {
|
||||
ser: self,
|
||||
end: Token::MapEnd,
|
||||
})
|
||||
} else {
|
||||
assert_next_token!(self, StructVariant { name, variant, len });
|
||||
Ok(Variant {
|
||||
ser: self,
|
||||
end: Token::StructVariantEnd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
panic!(
|
||||
"Types which have different human-readable and compact representations \
|
||||
must explicitly mark their test cases with `serde_test::Configure`"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeSeq for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
pub struct Variant<'s, 'a: 's> {
|
||||
ser: &'s mut Serializer<'a>,
|
||||
end: Token,
|
||||
}
|
||||
|
||||
impl<'s, 'a> ser::SerializeSeq for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::SeqEnd));
|
||||
assert_next_token!(self, SeqEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTuple for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeTuple for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleEnd));
|
||||
assert_next_token!(self, TupleEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTupleStruct for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeTupleStruct for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStructSep));
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::TupleStructEnd));
|
||||
assert_next_token!(self, TupleStructEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeTupleVariant for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeTupleVariant for Variant<'s, 'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep));
|
||||
value.serialize(&mut **self)
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd));
|
||||
match self.end {
|
||||
Token::TupleVariantEnd => assert_next_token!(self.ser, TupleVariantEnd),
|
||||
Token::SeqEnd => assert_next_token!(self.ser, SeqEnd),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeMap for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeMap for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapSep));
|
||||
key.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::MapEnd));
|
||||
assert_next_token!(self, MapEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeStruct for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeStruct for &'s mut Serializer<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self,
|
||||
key: &'static str,
|
||||
value: &T)
|
||||
-> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructSep));
|
||||
try!(key.serialize(&mut **self));
|
||||
key.serialize(&mut **self)?;
|
||||
value.serialize(&mut **self)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::StructEnd));
|
||||
assert_next_token!(self, StructEnd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, I> ser::SerializeStructVariant for &'s mut Serializer<'a, I>
|
||||
where I: Iterator<Item = &'a Token<'a>>
|
||||
{
|
||||
impl<'s, 'a> ser::SerializeStructVariant for Variant<'s, 'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T: ?Sized>(&mut self,
|
||||
key: &'static str,
|
||||
value: &T)
|
||||
-> Result<(), Self::Error>
|
||||
where T: Serialize
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep));
|
||||
try!(key.serialize(&mut **self));
|
||||
value.serialize(&mut **self)
|
||||
key.serialize(&mut *self.ser)?;
|
||||
value.serialize(&mut *self.ser)
|
||||
}
|
||||
|
||||
fn end(self) -> Result<(), Self::Error> {
|
||||
assert_eq!(self.tokens.next(), Some(&Token::EnumMapEnd));
|
||||
match self.end {
|
||||
Token::StructVariantEnd => assert_next_token!(self.ser, StructVariantEnd),
|
||||
Token::MapEnd => assert_next_token!(self.ser, MapEnd),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+489
-29
@@ -1,59 +1,519 @@
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Token<'a> {
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Token {
|
||||
/// A serialized `bool`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&true, &[Token::Bool(true)]);
|
||||
/// ```
|
||||
Bool(bool),
|
||||
|
||||
/// A serialized `i8`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i8, &[Token::I8(0)]);
|
||||
/// ```
|
||||
I8(i8),
|
||||
|
||||
/// A serialized `i16`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i16, &[Token::I16(0)]);
|
||||
/// ```
|
||||
I16(i16),
|
||||
|
||||
/// A serialized `i32`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i32, &[Token::I32(0)]);
|
||||
/// ```
|
||||
I32(i32),
|
||||
|
||||
/// A serialized `i64`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0i64, &[Token::I64(0)]);
|
||||
/// ```
|
||||
I64(i64),
|
||||
|
||||
/// A serialized `u8`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u8, &[Token::U8(0)]);
|
||||
/// ```
|
||||
U8(u8),
|
||||
|
||||
/// A serialized `u16`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u16, &[Token::U16(0)]);
|
||||
/// ```
|
||||
U16(u16),
|
||||
|
||||
/// A serialized `u32`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u32, &[Token::U32(0)]);
|
||||
/// ```
|
||||
U32(u32),
|
||||
|
||||
/// A serialized `u64`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0u64, &[Token::U64(0)]);
|
||||
/// ```
|
||||
U64(u64),
|
||||
|
||||
/// A serialized `f32`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0f32, &[Token::F32(0.0)]);
|
||||
/// ```
|
||||
F32(f32),
|
||||
|
||||
/// A serialized `f64`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&0f64, &[Token::F64(0.0)]);
|
||||
/// ```
|
||||
F64(f64),
|
||||
|
||||
/// A serialized `char`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&'\n', &[Token::Char('\n')]);
|
||||
/// ```
|
||||
Char(char),
|
||||
Str(&'a str),
|
||||
String(String),
|
||||
Bytes(&'a [u8]),
|
||||
ByteBuf(Vec<u8>),
|
||||
|
||||
Option(bool),
|
||||
/// A serialized `str`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s = String::from("transient");
|
||||
/// assert_tokens(&s, &[Token::Str("transient")]);
|
||||
/// ```
|
||||
Str(&'static str),
|
||||
|
||||
/// A borrowed `str`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s: &str = "borrowed";
|
||||
/// assert_tokens(&s, &[Token::BorrowedStr("borrowed")]);
|
||||
/// ```
|
||||
BorrowedStr(&'static str),
|
||||
|
||||
/// A serialized `String`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let s = String::from("owned");
|
||||
/// assert_tokens(&s, &[Token::String("owned")]);
|
||||
/// ```
|
||||
String(&'static str),
|
||||
|
||||
/// A serialized `[u8]`
|
||||
Bytes(&'static [u8]),
|
||||
|
||||
/// A borrowed `[u8]`.
|
||||
BorrowedBytes(&'static [u8]),
|
||||
|
||||
/// A serialized `ByteBuf`
|
||||
ByteBuf(&'static [u8]),
|
||||
|
||||
/// A serialized `Option<T>` containing none.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let opt = None::<char>;
|
||||
/// assert_tokens(&opt, &[Token::None]);
|
||||
/// ```
|
||||
None,
|
||||
|
||||
/// The header to a serialized `Option<T>` containing some value.
|
||||
///
|
||||
/// The tokens of the value follow after this header.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let opt = Some('c');
|
||||
/// assert_tokens(&opt, &[
|
||||
/// Token::Some,
|
||||
/// Token::Char('c'),
|
||||
/// ]);
|
||||
/// ```
|
||||
Some,
|
||||
|
||||
/// A serialized `()`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// assert_tokens(&(), &[Token::Unit]);
|
||||
/// ```
|
||||
Unit,
|
||||
UnitStruct(&'a str),
|
||||
|
||||
StructNewType(&'a str),
|
||||
/// A serialized unit struct of the given name.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct X;
|
||||
///
|
||||
/// assert_tokens(&X, &[Token::UnitStruct { name: "X" }]);
|
||||
/// # }
|
||||
/// ```
|
||||
UnitStruct { name: &'static str },
|
||||
|
||||
EnumStart(&'a str),
|
||||
EnumUnit(&'a str, &'a str),
|
||||
EnumNewType(&'a str, &'a str),
|
||||
/// A unit variant of an enum.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// enum E {
|
||||
/// A,
|
||||
/// }
|
||||
///
|
||||
/// let a = E::A;
|
||||
/// assert_tokens(&a, &[Token::UnitVariant { name: "E", variant: "A" }]);
|
||||
/// # }
|
||||
/// ```
|
||||
UnitVariant {
|
||||
name: &'static str,
|
||||
variant: &'static str,
|
||||
},
|
||||
|
||||
SeqStart(Option<usize>),
|
||||
SeqArrayStart(usize),
|
||||
SeqSep,
|
||||
/// The header to a serialized newtype struct of the given name.
|
||||
///
|
||||
/// After this header is the value contained in the newtype struct.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct N(String);
|
||||
///
|
||||
/// let n = N("newtype".to_owned());
|
||||
/// assert_tokens(&n, &[
|
||||
/// Token::NewtypeStruct { name: "N" },
|
||||
/// Token::String("newtype"),
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
NewtypeStruct { name: &'static str },
|
||||
|
||||
/// The header to a newtype variant of an enum.
|
||||
///
|
||||
/// After this header is the value contained in the newtype variant.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// enum E {
|
||||
/// B(u8),
|
||||
/// }
|
||||
///
|
||||
/// let b = E::B(0);
|
||||
/// assert_tokens(&b, &[
|
||||
/// Token::NewtypeVariant { name: "E", variant: "B" },
|
||||
/// Token::U8(0),
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
NewtypeVariant {
|
||||
name: &'static str,
|
||||
variant: &'static str,
|
||||
},
|
||||
|
||||
/// The header to a sequence.
|
||||
///
|
||||
/// After this header are the elements of the sequence, followed by
|
||||
/// `SeqEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let vec = vec!['a', 'b', 'c'];
|
||||
/// assert_tokens(&vec, &[
|
||||
/// Token::Seq { len: Some(3) },
|
||||
/// Token::Char('a'),
|
||||
/// Token::Char('b'),
|
||||
/// Token::Char('c'),
|
||||
/// Token::SeqEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
Seq { len: Option<usize> },
|
||||
|
||||
/// An indicator of the end of a sequence.
|
||||
SeqEnd,
|
||||
|
||||
TupleStart(usize),
|
||||
TupleSep,
|
||||
/// The header to a tuple.
|
||||
///
|
||||
/// After this header are the elements of the tuple, followed by `TupleEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// let tuple = ('a', 100);
|
||||
/// assert_tokens(&tuple, &[
|
||||
/// Token::Tuple { len: 2 },
|
||||
/// Token::Char('a'),
|
||||
/// Token::I32(100),
|
||||
/// Token::TupleEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
Tuple { len: usize },
|
||||
|
||||
/// An indicator of the end of a tuple.
|
||||
TupleEnd,
|
||||
|
||||
TupleStructStart(&'a str, usize),
|
||||
TupleStructSep,
|
||||
/// The header to a tuple struct.
|
||||
///
|
||||
/// After this header are the fields of the tuple struct, followed by
|
||||
/// `TupleStructEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct T(u8, u8);
|
||||
///
|
||||
/// let t = T(0, 0);
|
||||
/// assert_tokens(&t, &[
|
||||
/// Token::TupleStruct { name: "T", len: 2 },
|
||||
/// Token::U8(0),
|
||||
/// Token::U8(0),
|
||||
/// Token::TupleStructEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
TupleStruct { name: &'static str, len: usize },
|
||||
|
||||
/// An indicator of the end of a tuple struct.
|
||||
TupleStructEnd,
|
||||
|
||||
MapStart(Option<usize>),
|
||||
MapSep,
|
||||
/// The header to a tuple variant of an enum.
|
||||
///
|
||||
/// After this header are the fields of the tuple variant, followed by
|
||||
/// `TupleVariantEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// enum E {
|
||||
/// C(u8, u8),
|
||||
/// }
|
||||
///
|
||||
/// let c = E::C(0, 0);
|
||||
/// assert_tokens(&c, &[
|
||||
/// Token::TupleVariant { name: "E", variant: "C", len: 2 },
|
||||
/// Token::U8(0),
|
||||
/// Token::U8(0),
|
||||
/// Token::TupleVariantEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
TupleVariant {
|
||||
name: &'static str,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
},
|
||||
|
||||
/// An indicator of the end of a tuple variant.
|
||||
TupleVariantEnd,
|
||||
|
||||
/// The header to a map.
|
||||
///
|
||||
/// After this header are the entries of the map, followed by `MapEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
/// map.insert('A', 65);
|
||||
/// map.insert('Z', 90);
|
||||
///
|
||||
/// assert_tokens(&map, &[
|
||||
/// Token::Map { len: Some(2) },
|
||||
/// Token::Char('A'),
|
||||
/// Token::I32(65),
|
||||
/// Token::Char('Z'),
|
||||
/// Token::I32(90),
|
||||
/// Token::MapEnd,
|
||||
/// ]);
|
||||
/// ```
|
||||
Map { len: Option<usize> },
|
||||
|
||||
/// An indicator of the end of a map.
|
||||
MapEnd,
|
||||
|
||||
StructStart(&'a str, usize),
|
||||
StructSep,
|
||||
/// The header of a struct.
|
||||
///
|
||||
/// After this header are the fields of the struct, followed by `StructEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// struct S {
|
||||
/// a: u8,
|
||||
/// b: u8,
|
||||
/// }
|
||||
///
|
||||
/// let s = S { a: 0, b: 0 };
|
||||
/// assert_tokens(&s, &[
|
||||
/// Token::Struct { name: "S", len: 2 },
|
||||
/// Token::Str("a"),
|
||||
/// Token::U8(0),
|
||||
/// Token::Str("b"),
|
||||
/// Token::U8(0),
|
||||
/// Token::StructEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
Struct { name: &'static str, len: usize },
|
||||
|
||||
/// An indicator of the end of a struct.
|
||||
StructEnd,
|
||||
|
||||
EnumSeqStart(&'a str, &'a str, usize),
|
||||
EnumSeqSep,
|
||||
EnumSeqEnd,
|
||||
/// The header of a struct variant of an enum.
|
||||
///
|
||||
/// After this header are the fields of the struct variant, followed by
|
||||
/// `StructVariantEnd`.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// enum E {
|
||||
/// D { d: u8 },
|
||||
/// }
|
||||
///
|
||||
/// let d = E::D { d: 0 };
|
||||
/// assert_tokens(&d, &[
|
||||
/// Token::StructVariant { name: "E", variant: "D", len: 1 },
|
||||
/// Token::Str("d"),
|
||||
/// Token::U8(0),
|
||||
/// Token::StructVariantEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
StructVariant {
|
||||
name: &'static str,
|
||||
variant: &'static str,
|
||||
len: usize,
|
||||
},
|
||||
|
||||
EnumMapStart(&'a str, &'a str, usize),
|
||||
EnumMapSep,
|
||||
EnumMapEnd,
|
||||
/// An indicator of the end of a struct variant.
|
||||
StructVariantEnd,
|
||||
|
||||
/// The header to an enum of the given name.
|
||||
///
|
||||
/// ```edition2018
|
||||
/// # use serde::{Serialize, Deserialize};
|
||||
/// # use serde_test::{assert_tokens, Token};
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
/// enum E {
|
||||
/// A,
|
||||
/// B(u8),
|
||||
/// C(u8, u8),
|
||||
/// D { d: u8 },
|
||||
/// }
|
||||
///
|
||||
/// let a = E::A;
|
||||
/// assert_tokens(&a, &[
|
||||
/// Token::Enum { name: "E" },
|
||||
/// Token::Str("A"),
|
||||
/// Token::Unit,
|
||||
/// ]);
|
||||
///
|
||||
/// let b = E::B(0);
|
||||
/// assert_tokens(&b, &[
|
||||
/// Token::Enum { name: "E" },
|
||||
/// Token::Str("B"),
|
||||
/// Token::U8(0),
|
||||
/// ]);
|
||||
///
|
||||
/// let c = E::C(0, 0);
|
||||
/// assert_tokens(&c, &[
|
||||
/// Token::Enum { name: "E" },
|
||||
/// Token::Str("C"),
|
||||
/// Token::Seq { len: Some(2) },
|
||||
/// Token::U8(0),
|
||||
/// Token::U8(0),
|
||||
/// Token::SeqEnd,
|
||||
/// ]);
|
||||
///
|
||||
/// let d = E::D { d: 0 };
|
||||
/// assert_tokens(&d, &[
|
||||
/// Token::Enum { name: "E" },
|
||||
/// Token::Str("D"),
|
||||
/// Token::Map { len: Some(1) },
|
||||
/// Token::Str("d"),
|
||||
/// Token::U8(0),
|
||||
/// Token::MapEnd,
|
||||
/// ]);
|
||||
/// # }
|
||||
/// ```
|
||||
Enum { name: &'static str },
|
||||
}
|
||||
|
||||
impl Display for Token {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
+16
-8
@@ -1,18 +1,26 @@
|
||||
[package]
|
||||
name = "serde_test_suite"
|
||||
version = "0.0.0"
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>"]
|
||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
unstable-testing = ["compiletest_rs"]
|
||||
expandtest = []
|
||||
unstable = ["serde/unstable"]
|
||||
|
||||
[dependencies]
|
||||
serde = { path = "../serde" }
|
||||
|
||||
[build-dependencies]
|
||||
toolchain_find = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
fnv = "1.0"
|
||||
rustc-serialize = "0.3.16"
|
||||
serde = { path = "../serde" }
|
||||
serde_derive = { path = "../serde_derive" }
|
||||
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.2", optional = true }
|
||||
trybuild = { version = "1.0.19", features = ["diff"] }
|
||||
|
||||
@@ -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,8 +1,11 @@
|
||||
[package]
|
||||
name = "serde_derive_tests_no_std"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
serde = { path = "../../serde", default-features = false }
|
||||
serde_derive = { path = "../../serde_derive" }
|
||||
libc = { version = "0.2", default-features = false }
|
||||
serde = { path = "../../serde", default-features = false, features = ["derive"] }
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#![feature(lang_items, start, libc)]
|
||||
#![feature(lang_items, start)]
|
||||
#![no_std]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
#[start]
|
||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
0
|
||||
@@ -10,26 +8,18 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {}
|
||||
pub extern "C" fn rust_eh_personality() {}
|
||||
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe {
|
||||
libc::abort()
|
||||
libc::abort();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Unit;
|
||||
@@ -41,7 +31,9 @@ struct Newtype(u8);
|
||||
struct Tuple(u8, u8);
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Struct { f: u8 }
|
||||
struct Struct {
|
||||
f: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum Enum {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use serde::de::{Deserializer, Error, SeqAccess, Visitor};
|
||||
use std::fmt;
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_byte_buf(ByteBufVisitor)
|
||||
}
|
||||
|
||||
struct ByteBufVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ByteBufVisitor {
|
||||
type Value = Vec<u8>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("byte array")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let mut values = Vec::new();
|
||||
while let Some(value) = 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,8 +0,0 @@
|
||||
#[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,8 +0,0 @@
|
||||
#[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,10 +0,0 @@
|
||||
#[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,11 +0,0 @@
|
||||
#[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,10 +0,0 @@
|
||||
#[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,11 +0,0 @@
|
||||
#[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() {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user