diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /vendor/winnow | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/winnow')
51 files changed, 2106 insertions, 561 deletions
diff --git a/vendor/winnow/.cargo-checksum.json b/vendor/winnow/.cargo-checksum.json index 9dc595f45..bd4af0262 100644 --- a/vendor/winnow/.cargo-checksum.json +++ b/vendor/winnow/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"fbba351eeeef7391bab2512e3078a5dfe5be94742eef876eacbbd70d3b901769","Cargo.toml":"77ca17f5cffc130edd52c3894d0f23947c3b08e6bec4b1a9ab8b0b7d6973b979","LICENSE-MIT":"cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d","README.md":"b66d0e430d8a5f5391f1f51b2d7959c3881fca59fdf76a075129591b396c1c62","benches/contains_token.rs":"cd1ce72b8e1c92f8bd9539b1933e3337fedbc2e22f98959adb18b1a215f3cd70","benches/iter.rs":"bede3f156b87ffb8b901b092bcbb2717b7adf9a461a2fecdfad86025aad3e587","benches/number.rs":"f4b54895ed523c462ce327a5205b0b99591eb7056fe9de9abe3f809eff287386","examples/arithmetic/bench.rs":"ff0220a18c6004cca8b56583072fbb7290f022cc069f2d24be132f261ac55f18","examples/arithmetic/main.rs":"aab0793c96add893bbaacea331bc05de8f6b59e47c5bccca67bfd30e924cd790","examples/arithmetic/parser.rs":"ddb86007e2c6be97acd08788f30a13083e0615bf5314a625d74e6a72d69da43f","examples/arithmetic/parser_ast.rs":"748d238fac2fe83b6ab9dfad5d6a2bb5f1863f6c2a2757e17271053291da3990","examples/css/main.rs":"3127f259af57aaaa8363bfa6e0a64c9719173cc1dcc5a293771a2c8a7f31982e","examples/css/parser.rs":"7175cfdc36d228b3130f0cfc8565063554167998045a07f62644bbd90c2772b2","examples/custom_error.rs":"5ebf88007ed2ce998fdb16cd4326b1573e83f0c420e2f6561c10b6dd8ebf69a2","examples/http/bench.rs":"b6d3e9e5833b53ac58f8336617cc42a2f3f4c5e5ce88feb23184fcdbb36843f6","examples/http/main.rs":"95d3c73953cd76ea462d886ade2ab34e987239bae3abb0349c434fb01b80467d","examples/http/parser.rs":"55a5894ab8e211a17f2eb9db72503579704d85376a6631a741eede2bfcd4bdbd","examples/http/parser_streaming.rs":"1300486af4dfcfe9b1b396436ef58927663624b0184b9c70a636e639c09c4552","examples/ini/bench.rs":"c8fd1aed25ce2878c0f440d765779d7877e83ca202cf071f8f4c57566596bf89","examples/ini/main.rs":"d771aa8aae11e53f4f5453ac39e10ae3a1de210408dfd31ca7d1ce58d14c3fb9","examples/ini/parser.rs":"c554286e8f2077f999d607902e7a63ce3945939118bccf830a68b22bfe24c775","examples/ini/parser_str.rs":"8f5bce75153ae98d5e76f884fec4746a73c44c4fb9a3c4c2efdf77913baf3bec","examples/iterator.rs":"21fb0480749116407689162f0d3e9957e3e7b6863f9dda08ee01af675409b06e","examples/json/bench.rs":"9479248ccef46e0741e0eebf9fb3b307b343ba665925481adc4554d8e65f9d39","examples/json/json.rs":"48cf6c114098113c9767bebe430682f55f7c1a227e6486131ca58c00770711f2","examples/json/main.rs":"7ab1f6eefd4eb61153cf05991e593fd10827ac09f66af45d3019f94c39c5b84e","examples/json/parser.rs":"6a49d300a323bfab9deb9221c92c44ea4b5738788077f712cc8d12d082583127","examples/json/parser_dispatch.rs":"370ae21b2c1f9fe848a8ca0d9f821109ab0995c78575d01a0abe32715429eb41","examples/json/parser_partial.rs":"4f944c45223161fcbb6025fb8e71306e549ab39bf62d26bcbf85c61d124b18e2","examples/json_iterator.rs":"070f7ade176b04b70b026b1915601a52fbb462ec0cc7b9d6684d1e0a04c2d031","examples/ndjson/example.ndjson":"c44c130731008bca76181348d40f46b183577949b5a4d229e0e1a56e1e405e5d","examples/ndjson/main.rs":"dc92dd5d76b5d43edf947b6455d552f0212e46d59c926d95f97f5d159b14e361","examples/ndjson/parser.rs":"e10c0940da97def0a9c628916433cb867ea1a8cc6ecc0dff58bc98d13ec47ccd","examples/s_expression/main.rs":"5a2de0b477807c7d6ab8bb72579f03692e8f5ea89d5b6f3a8342cfdbe4d84b96","examples/s_expression/parser.rs":"a98fa7a2230d3c2aa77206bed66d7c4167707464bdb790f2ab25d803813589e3","examples/string/main.rs":"e6362f957d532d41bcd96476e55ac4c253eb04fa25ee88b48d872661a46a5bb5","examples/string/parser.rs":"111c8b67d9e51eef8b980f4efb9264d76598cb09e820b74f9ea8dfec5176abb4","src/_topic/arithmetic.rs":"94920a9572ed6deac58abb337a7be57b93cf37440f0cc3eaf514cb9ad9b9e077","src/_topic/error.rs":"69c972c609a91e078ddb4e01da8f3d35f29d8dbcb077614e9b156c033c9f5dd7","src/_topic/fromstr.rs":"01abdab296cd30067ae5f508b2b21ebe97c0571ace58e7817876eb2110e8d23a","src/_topic/http.rs":"19b9ec78a031fe5b3086fb34d04d6c13308c50b6e7bfe30229f5b682d3605ac8","src/_topic/ini.rs":"b2b04d48eac3158f4e26ee9dce748a699d02acaa0b12ae8d54421cad0fdc4ad7","src/_topic/json.rs":"bde39ee6b1c5fab2d2da480822b737674aed877f92c3f748d6932bec313b5661","src/_topic/language.rs":"437814054d4a0a19ffccd74ff9189677e6a8e9df45dc395861fc75d5bd23719b","src/_topic/mod.rs":"7e871bc9f8838ab2b7bf35db6800e17a19bf8132675e305087cb6dd1e841cbec","src/_topic/partial.rs":"5b795d1a8f2fa5a378c4974f9862acd479392a645b93c5dc4da2c4b1384c0d0d","src/_topic/performance.rs":"1f2f56fb70a70d5f8890deea25fa6a5df9a97d489380db0e0cf84eaa1b7806df","src/_topic/s_expression.rs":"6ca9a22a5c3344e120421f2ab353a1e822777aebfa1faa0acffc9632f7668cb2","src/_topic/stream.rs":"5ae58b8a53e7ffe60df4fbe862fbc2319f5c36f798767b7b650dd6441332042b","src/_topic/why.rs":"7805a9f27b64d253982b32ecf16963f2acc092f507da929766db5e4a554feaed","src/_tutorial/chapter_0.rs":"a86301c783ff7f3f5d7a870963fc9557347c1e1819b5acae04cc70510ada4d0d","src/_tutorial/chapter_1.rs":"c42f66bb480862dd5e46b5a992529ec354befd54aa167c24291a2e63d4f20631","src/_tutorial/chapter_2.rs":"402335520bc1303de310a0f60729816f1899af9613457676b723ad1940dfe9c3","src/_tutorial/chapter_3.rs":"8e9eca4a742c86da8edc084b873ef915acd5f97ee32e13ea1eaa0b93c90734ad","src/_tutorial/chapter_4.rs":"15d19c9ebb53f7a4ad7effb49a086be60b0bbe210d3aa65d161edf83c13d3608","src/_tutorial/chapter_5.rs":"bdf668e5121b5c8d7c4658d5d8360781cc93279f451a5e00b6c3d0cf8c3634a1","src/_tutorial/chapter_6.rs":"0ade4cfdab6f01e2f7c20be273ce6379728a2f4ee6f855fb29f8c2efc391d030","src/_tutorial/chapter_7.rs":"0767623ca13b97ab32df54c3d0b1d58c55b97d7aad25259687bdc59bf62cfef4","src/_tutorial/mod.rs":"69dc414df5be09f176c36ecee72605203c3aaa1bde77b55af012d9fd8c57a789","src/ascii/mod.rs":"9891ba592aa3a1ca188a2da3e1fb0bccf85b670f5a0a2cd154b546fa12e4a1e7","src/ascii/tests.rs":"cbd0d7db9eb795762de305fde5204ee70396cb384ac7826bde91bf9c69cbec74","src/binary/bits/mod.rs":"104b9f4435369c83f3def181eeb2a4bd8795a49738453013732ed49aebf3076a","src/binary/bits/tests.rs":"1ce1707a8ab2300d601f67fb3cb9c4b8ba7528564477e65ff25d8542c3e0f6e7","src/binary/mod.rs":"6447ddb0d1f87ee653c4cc629fbc60714228d236fb6dad68ff0994df2c239d84","src/binary/tests.rs":"bc8c383d345e9d63f09d3edb6e4ff76b8e6d422f2359f7e7b2b29c56082d3b93","src/combinator/branch.rs":"49714533de587e11a9a3dbd7a8d86a554b76681bf0911ea6f8f98e9181607995","src/combinator/core.rs":"632201f917e732b80c8dbe88c43f33e868df5261449b22b18e60424a795e0f45","src/combinator/mod.rs":"a3eb82c52c4b707a84d60c6d9da85da76b3a9004b1d5f0e0029844d45143322c","src/combinator/multi.rs":"7a7acdbb667617627c1af7fb601bf1ec48df589e89744023ea32ce0eff1e4eaa","src/combinator/parser.rs":"1ee72502cf05c476aa77ef20744abe2bf1ea9d04504cf6d13a3f9f91d2c78cf5","src/combinator/sequence.rs":"f913aec935bbdb1fd496e76dbc14d697d8e7e48c163856e062c5ded2f3170905","src/combinator/tests.rs":"b404f2047e717e073a8a45cf33db996ef69df8759ab14e9aa8d32613d0cd3beb","src/error.rs":"2ab9bdbca725625c6d2dad0b277127cd88e16c9137c2f8a3cc6e09f273fba04e","src/lib.rs":"3436ea3a7ca6375c49a62c674ad348b3601eb5d969b7376aeb19d395a24d2c63","src/macros.rs":"401a510f19ee4acc180c8dc1fd3c0a0c0e7bc50d69ffc4a925439e88f3299547","src/parser.rs":"1299d12c3facbbfb0336c53412b5c14d1dca6708e83ba847383b969bad6a24d9","src/stream/impls.rs":"99f69fdb8c32ad1f759bcc414ebfd2428eac5997887ce2b6946a2fcfcd174082","src/stream/mod.rs":"ff2cd9b3e145c029f3a1d348d0559c747516584301624e3d18b4b4790bcd8359","src/stream/tests.rs":"e351ea68ba3fbeaeeac147ac7c186d8ee3a17ff09c78c016dd294eb0719d54f2","src/token/mod.rs":"99689541315f795e57983566aab3c641ccf711492a2e397af15213a63b6cb702","src/token/tests.rs":"65819246fac1c10abe4abeeb79e30fb03b06a9a5ef6fde3edec003ad1f034f78","src/trace/internals.rs":"3480e946ba22390ac84046487728fd89d78cb3bc5547305162ed925e2437802f","src/trace/mod.rs":"7614deec7a51082464ae6ff99302bf9d8d1b11d4c6d509254cae045a913c1571"},"package":"7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"}
\ No newline at end of file +{"files":{"Cargo.lock":"dd16728417bc64167c83aecb80ad25367fd7cdb8d635d6bbda2f4f569fe344d6","Cargo.toml":"21e2eac70534f919d2dd269e8c0a6860b7a53ac1670edf0256890bfb95158645","LICENSE-MIT":"cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d","README.md":"0b7e4cad5ef0cbb47dc1c1c34ff3b5d090aaba2cc3b3c5401539e5c4a22b7938","benches/contains_token.rs":"20e765de27f0ad9bf549e250bdb67d73714d23bc10bb67be240a258dcf8b6ed7","benches/find_slice.rs":"c140d235fb94997b365e5e66c6caf77ef8b782f80cfce580ef68aa8e300fdb70","benches/iter.rs":"bede3f156b87ffb8b901b092bcbb2717b7adf9a461a2fecdfad86025aad3e587","benches/number.rs":"f4b54895ed523c462ce327a5205b0b99591eb7056fe9de9abe3f809eff287386","examples/arithmetic/bench.rs":"a162e4f91ce2ed19b5b53f79d77c92eb52278f0788da9af8fee3ee62cebfe0a9","examples/arithmetic/main.rs":"b7f2090beefa76ca324d23bc62e06ef97df8c7d02934998f4ddce1ac45e0b852","examples/arithmetic/parser.rs":"c219b2ff9a4f9bb4db97899203294765e72024fe4324b3d46d0b464258757da6","examples/arithmetic/parser_ast.rs":"5897edec836e91d0fcb6764894d0cb67898990a0c3cbde3ffc1fc43777127fa6","examples/arithmetic/parser_lexer.rs":"a0f79926cc06c9581ca73071355d6d44a070e40773a0c92271edcd5ed80bb93f","examples/css/main.rs":"3127f259af57aaaa8363bfa6e0a64c9719173cc1dcc5a293771a2c8a7f31982e","examples/css/parser.rs":"7175cfdc36d228b3130f0cfc8565063554167998045a07f62644bbd90c2772b2","examples/custom_error.rs":"5ebf88007ed2ce998fdb16cd4326b1573e83f0c420e2f6561c10b6dd8ebf69a2","examples/http/bench.rs":"b6d3e9e5833b53ac58f8336617cc42a2f3f4c5e5ce88feb23184fcdbb36843f6","examples/http/main.rs":"95d3c73953cd76ea462d886ade2ab34e987239bae3abb0349c434fb01b80467d","examples/http/parser.rs":"23682838bdce549beddf9c8c869a9f1b7531d651198989b03df68058b1f75bfc","examples/http/parser_streaming.rs":"56e7088ed5a32ef9b6ff114f67da33479edb3a5b673f88f3b851d7f504cbc6e5","examples/ini/bench.rs":"c8fd1aed25ce2878c0f440d765779d7877e83ca202cf071f8f4c57566596bf89","examples/ini/main.rs":"d771aa8aae11e53f4f5453ac39e10ae3a1de210408dfd31ca7d1ce58d14c3fb9","examples/ini/parser.rs":"c554286e8f2077f999d607902e7a63ce3945939118bccf830a68b22bfe24c775","examples/ini/parser_str.rs":"5eb333cd192aff09138fa1578628f76c19a9b48375c9f13860deb34cf1a6df37","examples/iterator.rs":"21fb0480749116407689162f0d3e9957e3e7b6863f9dda08ee01af675409b06e","examples/json/bench.rs":"9479248ccef46e0741e0eebf9fb3b307b343ba665925481adc4554d8e65f9d39","examples/json/json.rs":"48cf6c114098113c9767bebe430682f55f7c1a227e6486131ca58c00770711f2","examples/json/main.rs":"7ab1f6eefd4eb61153cf05991e593fd10827ac09f66af45d3019f94c39c5b84e","examples/json/parser.rs":"747e6d206cf72a471c3fef7a7a6df102c9b907e9b642057ba010b1a805eaa011","examples/json/parser_dispatch.rs":"e430b5fdfa8c9f4a2312657e8f4451101b5492019404bcbe0950c0c6007f959b","examples/json/parser_partial.rs":"a22a908248082f61b6d30c6a7a0d9d31147ce15cc850a9f117657b9e59f16260","examples/json_iterator.rs":"2a8a842b43fdea12a6b5c4927cede23cbd0eb96bb1cbf42a794103fc9be9ff3a","examples/ndjson/example.ndjson":"c44c130731008bca76181348d40f46b183577949b5a4d229e0e1a56e1e405e5d","examples/ndjson/main.rs":"dc92dd5d76b5d43edf947b6455d552f0212e46d59c926d95f97f5d159b14e361","examples/ndjson/parser.rs":"7699f08c0dc5d8e3a4ef488d5f9eb8de996046669ec988bd9dc7aa322168e57d","examples/s_expression/main.rs":"5a2de0b477807c7d6ab8bb72579f03692e8f5ea89d5b6f3a8342cfdbe4d84b96","examples/s_expression/parser.rs":"2a468bf61e4aed9aa5c556fb19c479060d121f60671865324675ab9fd92f0ddd","examples/string/main.rs":"e6362f957d532d41bcd96476e55ac4c253eb04fa25ee88b48d872661a46a5bb5","examples/string/parser.rs":"5a08324b3054fb4cc3a29164e91bdf4811f9f85deb38418603c22f4931a540b5","src/_topic/arithmetic.rs":"28d61dd492b308209d534c54813ea48ac1862a39196527042180de7718f915d0","src/_topic/error.rs":"69c972c609a91e078ddb4e01da8f3d35f29d8dbcb077614e9b156c033c9f5dd7","src/_topic/fromstr.rs":"01abdab296cd30067ae5f508b2b21ebe97c0571ace58e7817876eb2110e8d23a","src/_topic/http.rs":"19b9ec78a031fe5b3086fb34d04d6c13308c50b6e7bfe30229f5b682d3605ac8","src/_topic/ini.rs":"b2b04d48eac3158f4e26ee9dce748a699d02acaa0b12ae8d54421cad0fdc4ad7","src/_topic/json.rs":"bde39ee6b1c5fab2d2da480822b737674aed877f92c3f748d6932bec313b5661","src/_topic/language.rs":"437814054d4a0a19ffccd74ff9189677e6a8e9df45dc395861fc75d5bd23719b","src/_topic/mod.rs":"00e7cd3580584270652890193653ded7791211a4568469260ce0214d68de35fd","src/_topic/partial.rs":"9edb967fcda9392cb417370bd34cd946f5eceb5f02f0812ba769c2782e7a9ced","src/_topic/performance.rs":"115b636769c307bd80ecc5b89ffad47877352bc93ef47bf664093d3d7a2562cc","src/_topic/s_expression.rs":"6ca9a22a5c3344e120421f2ab353a1e822777aebfa1faa0acffc9632f7668cb2","src/_topic/stream.rs":"acc1e8942e27fec3911c562934be6bf9b096d436593af50a4418d9e0fe607535","src/_topic/why.rs":"7c328fcdce718ba342052a652440105f7191416005a7ed23925297db4edd141b","src/_tutorial/chapter_0.rs":"c0512cb9857edb9df0ac1d327fccb1e950019b9a417959c802714039038b8bce","src/_tutorial/chapter_1.rs":"743847b36faab89235f7e4d36076b5090d1dff7c0f5f38f9c3387aaff80bbec2","src/_tutorial/chapter_2.rs":"3671bfd14e7a9c6c630daac8bc2c8128938fd0f830a5524c33a800d06d4cd205","src/_tutorial/chapter_3.rs":"268d0fa4d799480653cc025b7c4af206345f9d45fe014776dbcfbb85bf5b893a","src/_tutorial/chapter_4.rs":"4390d7ec2a67a726bd8df7f62ebd3fc26df926e79c014b8a2e623ec3e4c1ca25","src/_tutorial/chapter_5.rs":"25656769ea285f9d6d3780294a24491b27918cecd754b430220b56ac2047a10c","src/_tutorial/chapter_6.rs":"51fae6d7479288f518d04d43b3e987aa0f26f83ff0620ca4bdcfe7ec92e2e0cb","src/_tutorial/chapter_7.rs":"0767623ca13b97ab32df54c3d0b1d58c55b97d7aad25259687bdc59bf62cfef4","src/_tutorial/mod.rs":"afbc50be8c274db7b3963b74865c527e85f8b90b83e18c32edc1baca952c0957","src/ascii/mod.rs":"673e2b5463c4c84fec23aea0e8f5380b0abc4e08893ae1d1fdd5bd84e5cbc58d","src/ascii/tests.rs":"cbd0d7db9eb795762de305fde5204ee70396cb384ac7826bde91bf9c69cbec74","src/binary/bits/mod.rs":"5f64c2badc4de4e336e6fcdf6bf0c051b1b1d1acce1ca8da8f841b3ca7681762","src/binary/bits/tests.rs":"1ce1707a8ab2300d601f67fb3cb9c4b8ba7528564477e65ff25d8542c3e0f6e7","src/binary/mod.rs":"6447ddb0d1f87ee653c4cc629fbc60714228d236fb6dad68ff0994df2c239d84","src/binary/tests.rs":"bc8c383d345e9d63f09d3edb6e4ff76b8e6d422f2359f7e7b2b29c56082d3b93","src/combinator/branch.rs":"49714533de587e11a9a3dbd7a8d86a554b76681bf0911ea6f8f98e9181607995","src/combinator/core.rs":"7fe951f5b5084338ea4f8387b344c297b96a177249ceea7ed65d1ef17ba27bb5","src/combinator/mod.rs":"640334814dbdca048178c50e8fe9a9984c4a025c0d371dfd5ed42dac9f959d6d","src/combinator/multi.rs":"5e7575fc085b91afbe610dbc90c46538a4620a67c0bc51c8a88f4de441fc3dab","src/combinator/parser.rs":"79889d727ea81cb276845df08d3ae80aea0915c6941dd961f33509da995a7c3e","src/combinator/sequence.rs":"f913aec935bbdb1fd496e76dbc14d697d8e7e48c163856e062c5ded2f3170905","src/combinator/tests.rs":"b13fd6e0516d73d4ec2733813dea763d1599a19c5ce2f7309b7e5e3d4acabc0b","src/error.rs":"64e43d63db6c5a5c64270b61d94719199c9ea9d329a13042b01a1bf35b1fa2e8","src/lib.rs":"472b0ffc01ba9551b7e46e8eb93300c225f0ad8a58f70b9dce54b029a7bbf79d","src/macros.rs":"401a510f19ee4acc180c8dc1fd3c0a0c0e7bc50d69ffc4a925439e88f3299547","src/parser.rs":"71c9ddca1fa704189cb5c0f68b5bede0dfd77c985b9fa61e9efa63a70c57aa3b","src/stream/impls.rs":"139025ed7c350c86e14b3a23019b1e5569cfee98c5f3e07d5a7dc69f411a8730","src/stream/mod.rs":"a787a62cf7a1ac2f6bdf6197c58c8ce3def4757fd5b6e0508f623fc24db7532d","src/stream/tests.rs":"48b73121ca32e6357f080e66915b7697028d0c807e3908df4fde9758f9f679e5","src/token/mod.rs":"0509c5a93870f20957d0be31a45021438b17aa25004eaf1db9898028c536edcd","src/token/tests.rs":"e6505392a729962bcda559bc21176eb5d77811f63169203eae03e36df71683ed","src/trace/internals.rs":"3480e946ba22390ac84046487728fd89d78cb3bc5547305162ed925e2437802f","src/trace/mod.rs":"767e5ac4dd698f17a61494eea288cf216f9920919a9b8e9b2547b3fe6cc470db"},"package":"b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94"}
\ No newline at end of file diff --git a/vendor/winnow/Cargo.lock b/vendor/winnow/Cargo.lock index 2e2dfe5de..25cdb72ee 100644 --- a/vendor/winnow/Cargo.lock +++ b/vendor/winnow/Cargo.lock @@ -863,6 +863,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] name = "rustix" version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1391,7 +1397,7 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.25" dependencies = [ "anstream", "anstyle", @@ -1403,6 +1409,7 @@ dependencies = [ "lexopt", "memchr", "proptest", + "rustc-hash", "snapbox", "term-transcript", "terminal_size", diff --git a/vendor/winnow/Cargo.toml b/vendor/winnow/Cargo.toml index a44df6680..e0ef24f69 100644 --- a/vendor/winnow/Cargo.toml +++ b/vendor/winnow/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.64.0" name = "winnow" -version = "0.5.15" +version = "0.5.25" include = [ "build.rs", "src/**/*", @@ -142,12 +142,17 @@ required-features = ["alloc"] name = "arithmetic" path = "examples/arithmetic/bench.rs" harness = false +required-features = ["alloc"] [[bench]] name = "contains_token" harness = false [[bench]] +name = "find_slice" +harness = false + +[[bench]] name = "iter" harness = false @@ -212,6 +217,9 @@ version = "0.3.0" [dev-dependencies.proptest] version = "1.2.0" +[dev-dependencies.rustc-hash] +version = "1.1.0" + [dev-dependencies.snapbox] version = "0.4.11" features = ["examples"] diff --git a/vendor/winnow/README.md b/vendor/winnow/README.md index 507df4e42..5530657c9 100644 --- a/vendor/winnow/README.md +++ b/vendor/winnow/README.md @@ -19,7 +19,7 @@ For more details, see: # Contributors winnow is the fruit of the work of many contributors over the years, many -thanks for your help! In particular, thanks to [Geal](https://github.com/Geal) +thanks for your help! In particular, thanks to [Geal](https://github.com/Geal) for the original [`nom` crate](https://crates.io/crates/nom). <a href="https://github.com/winnow-rs/winnow/graphs/contributors"> diff --git a/vendor/winnow/benches/contains_token.rs b/vendor/winnow/benches/contains_token.rs index 2980ce6c8..675b08e58 100644 --- a/vendor/winnow/benches/contains_token.rs +++ b/vendor/winnow/benches/contains_token.rs @@ -3,7 +3,7 @@ use criterion::black_box; use winnow::combinator::alt; use winnow::combinator::repeat; use winnow::prelude::*; -use winnow::token::take_till1; +use winnow::token::take_till; use winnow::token::take_while; fn contains_token(c: &mut criterion::Criterion) { @@ -52,17 +52,29 @@ fn contains_token(c: &mut criterion::Criterion) { fn parser_slice(input: &mut &str) -> PResult<usize> { let contains = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..]; - repeat(0.., alt((take_while(1.., contains), take_till1(contains)))).parse_next(input) + repeat( + 0.., + alt((take_while(1.., contains), take_till(1.., contains))), + ) + .parse_next(input) } fn parser_array(input: &mut &str) -> PResult<usize> { let contains = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - repeat(0.., alt((take_while(1.., contains), take_till1(contains)))).parse_next(input) + repeat( + 0.., + alt((take_while(1.., contains), take_till(1.., contains))), + ) + .parse_next(input) } fn parser_tuple(input: &mut &str) -> PResult<usize> { let contains = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); - repeat(0.., alt((take_while(1.., contains), take_till1(contains)))).parse_next(input) + repeat( + 0.., + alt((take_while(1.., contains), take_till(1.., contains))), + ) + .parse_next(input) } fn parser_closure_or(input: &mut &str) -> PResult<usize> { @@ -78,12 +90,20 @@ fn parser_closure_or(input: &mut &str) -> PResult<usize> { || c == '8' || c == '9' }; - repeat(0.., alt((take_while(1.., contains), take_till1(contains)))).parse_next(input) + repeat( + 0.., + alt((take_while(1.., contains), take_till(1.., contains))), + ) + .parse_next(input) } fn parser_closure_matches(input: &mut &str) -> PResult<usize> { let contains = |c: char| matches!(c, '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'); - repeat(0.., alt((take_while(1.., contains), take_till1(contains)))).parse_next(input) + repeat( + 0.., + alt((take_while(1.., contains), take_till(1.., contains))), + ) + .parse_next(input) } const CONTIGUOUS: &str = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; diff --git a/vendor/winnow/benches/find_slice.rs b/vendor/winnow/benches/find_slice.rs new file mode 100644 index 000000000..226fcadbf --- /dev/null +++ b/vendor/winnow/benches/find_slice.rs @@ -0,0 +1,50 @@ +use criterion::black_box; + +use winnow::combinator::repeat; +use winnow::prelude::*; +use winnow::token::take_until0; + +fn find_slice(c: &mut criterion::Criterion) { + let empty = ""; + let start_byte = "\r".repeat(100); + let start_slice = "\r\n".repeat(100); + let small = format!("{:>10}\r\n", "").repeat(100); + let large = format!("{:>10000}\r\n", "").repeat(100); + + let data = [ + ("empty", (empty, empty)), + ("start", (&start_byte, &start_slice)), + ("medium", (&small, &small)), + ("large", (&large, &large)), + ]; + let mut group = c.benchmark_group("find_slice"); + for (name, samples) in data { + group.bench_with_input( + criterion::BenchmarkId::new("byte", name), + samples.0, + |b, sample| { + b.iter(|| black_box(parser_byte.parse_peek(black_box(sample)).unwrap())); + }, + ); + + group.bench_with_input( + criterion::BenchmarkId::new("slice", name), + samples.1, + |b, sample| { + b.iter(|| black_box(parser_slice.parse_peek(black_box(sample)).unwrap())); + }, + ); + } + group.finish(); +} + +fn parser_byte(input: &mut &str) -> PResult<usize> { + repeat(0.., (take_until0("\r"), "\r")).parse_next(input) +} + +fn parser_slice(input: &mut &str) -> PResult<usize> { + repeat(0.., (take_until0("\r\n"), "\r\n")).parse_next(input) +} + +criterion::criterion_group!(benches, find_slice); +criterion::criterion_main!(benches); diff --git a/vendor/winnow/examples/arithmetic/bench.rs b/vendor/winnow/examples/arithmetic/bench.rs index 6504454c4..692ac22c9 100644 --- a/vendor/winnow/examples/arithmetic/bench.rs +++ b/vendor/winnow/examples/arithmetic/bench.rs @@ -1,19 +1,31 @@ mod parser; +mod parser_ast; +mod parser_lexer; use winnow::prelude::*; -use parser::expr; - #[allow(clippy::eq_op, clippy::erasing_op)] fn arithmetic(c: &mut criterion::Criterion) { - let data = " 2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2));"; + let data = " 2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2))"; + let expected = 2 * 2 / (5 - 1) + 3 * (1 + 2 * (45 / 2)); + assert_eq!(parser::expr.parse(data), Ok(expected)); + assert_eq!( + parser_ast::expr.parse(data).map(|ast| ast.eval()), + Ok(expected) + ); assert_eq!( - expr.parse_peek(data), - Ok((";", 2 * 2 / (5 - 1) + 3 * (1 + 2 * (45 / 2)),)) + parser_lexer::expr2.parse(data).map(|ast| ast.eval()), + Ok(expected) ); - c.bench_function("arithmetic", |b| { - b.iter(|| expr.parse_peek(data).unwrap()); + c.bench_function("direct", |b| { + b.iter(|| parser::expr.parse(data).unwrap()); + }); + c.bench_function("ast", |b| { + b.iter(|| parser_ast::expr.parse(data).unwrap().eval()); + }); + c.bench_function("lexer", |b| { + b.iter(|| parser_lexer::expr2.parse_peek(data).unwrap()); }); } diff --git a/vendor/winnow/examples/arithmetic/main.rs b/vendor/winnow/examples/arithmetic/main.rs index 94a17d85d..e46cf2f44 100644 --- a/vendor/winnow/examples/arithmetic/main.rs +++ b/vendor/winnow/examples/arithmetic/main.rs @@ -2,32 +2,41 @@ use winnow::prelude::*; mod parser; mod parser_ast; +mod parser_lexer; fn main() -> Result<(), lexopt::Error> { let args = Args::parse()?; let input = args.input.as_deref().unwrap_or("1 + 1"); + if let Err(err) = calc(input, args.implementation) { + println!("FAILED"); + println!("{}", err); + } + + Ok(()) +} +fn calc( + input: &str, + imp: Impl, +) -> Result<(), winnow::error::ParseError<&str, winnow::error::ContextError>> { println!("{} =", input); - match args.implementation { - Impl::Eval => match parser::expr.parse(input) { - Ok(result) => { - println!(" {}", result); - } - Err(err) => { - println!(" {}", err); - } - }, - Impl::Ast => match parser_ast::expr.parse(input) { - Ok(result) => { - println!(" {:#?}", result); - } - Err(err) => { - println!(" {}", err); - } - }, + match imp { + Impl::Eval => { + let result = parser::expr.parse(input)?; + println!(" {}", result); + } + Impl::Ast => { + let result = parser_ast::expr.parse(input)?; + println!(" {:#?}={}", result, result.eval()); + } + Impl::Lexer => { + let tokens = parser_lexer::lex.parse(input)?; + println!(" {:#?}", tokens); + let result = parser_lexer::expr.parse(tokens.as_slice()).unwrap(); + println!(" {:#?}={}", result, result.eval()); + } } - Ok(()) } @@ -40,6 +49,7 @@ struct Args { enum Impl { Eval, Ast, + Lexer, } impl Default for Impl { @@ -61,6 +71,7 @@ impl Args { res.implementation = args.value()?.parse_with(|s| match s { "eval" => Ok(Impl::Eval), "ast" => Ok(Impl::Ast), + "lexer" => Ok(Impl::Lexer), _ => Err("expected `eval`, `ast`"), })?; } diff --git a/vendor/winnow/examples/arithmetic/parser.rs b/vendor/winnow/examples/arithmetic/parser.rs index 50ffbdbbb..165727515 100644 --- a/vendor/winnow/examples/arithmetic/parser.rs +++ b/vendor/winnow/examples/arithmetic/parser.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use winnow::prelude::*; use winnow::{ - ascii::{digit1 as digits, space0 as spaces}, + ascii::{digit1 as digits, multispace0 as multispaces}, combinator::alt, combinator::delimited, combinator::fold_repeat, @@ -50,53 +50,88 @@ fn term(i: &mut &str) -> PResult<i64> { .parse_next(i) } -// We transform an integer string into a i64, ignoring surrounding whitespaces +// We transform an integer string into a i64, ignoring surrounding whitespace // We look for a digit suite, and try to convert it. // If either str::from_utf8 or FromStr::from_str fail, // we fallback to the parens parser defined above fn factor(i: &mut &str) -> PResult<i64> { delimited( - spaces, - alt(( - digits.try_map(FromStr::from_str), - delimited('(', expr, ')'), - parens, - )), - spaces, + multispaces, + alt((digits.try_map(FromStr::from_str), parens)), + multispaces, ) .parse_next(i) } -// We parse any expr surrounded by parens, ignoring all whitespaces around those +// We parse any expr surrounded by parens, ignoring all whitespace around those fn parens(i: &mut &str) -> PResult<i64> { delimited('(', expr, ')').parse_next(i) } #[test] fn factor_test() { - assert_eq!(factor.parse_peek("3"), Ok(("", 3))); - assert_eq!(factor.parse_peek(" 12"), Ok(("", 12))); - assert_eq!(factor.parse_peek("537 "), Ok(("", 537))); - assert_eq!(factor.parse_peek(" 24 "), Ok(("", 24))); + let input = "3"; + let expected = Ok(("", 3)); + assert_eq!(factor.parse_peek(input), expected); + + let input = " 12"; + let expected = Ok(("", 12)); + assert_eq!(factor.parse_peek(input), expected); + + let input = "537 "; + let expected = Ok(("", 537)); + assert_eq!(factor.parse_peek(input), expected); + + let input = " 24 "; + let expected = Ok(("", 24)); + assert_eq!(factor.parse_peek(input), expected); } #[test] fn term_test() { - assert_eq!(term.parse_peek(" 12 *2 / 3"), Ok(("", 8))); - assert_eq!(term.parse_peek(" 2* 3 *2 *2 / 3"), Ok(("", 8))); - assert_eq!(term.parse_peek(" 48 / 3/2"), Ok(("", 8))); + let input = " 12 *2 / 3"; + let expected = Ok(("", 8)); + assert_eq!(term.parse_peek(input), expected); + + let input = " 12 *2 / 3"; + let expected = Ok(("", 8)); + assert_eq!(term.parse_peek(input), expected); + + let input = " 2* 3 *2 *2 / 3"; + let expected = Ok(("", 8)); + assert_eq!(term.parse_peek(input), expected); + + let input = " 48 / 3/2"; + let expected = Ok(("", 8)); + assert_eq!(term.parse_peek(input), expected); } #[test] fn expr_test() { - assert_eq!(expr.parse_peek(" 1 + 2 "), Ok(("", 3))); - assert_eq!(expr.parse_peek(" 12 + 6 - 4+ 3"), Ok(("", 17))); - assert_eq!(expr.parse_peek(" 1 + 2*3 + 4"), Ok(("", 11))); + let input = " 1 + 2 "; + let expected = Ok(("", 3)); + assert_eq!(expr.parse_peek(input), expected); + + let input = " 12 + 6 - 4+ 3"; + let expected = Ok(("", 17)); + assert_eq!(expr.parse_peek(input), expected); + + let input = " 1 + 2*3 + 4"; + let expected = Ok(("", 11)); + assert_eq!(expr.parse_peek(input), expected); } #[test] fn parens_test() { - assert_eq!(expr.parse_peek(" ( 2 )"), Ok(("", 2))); - assert_eq!(expr.parse_peek(" 2* ( 3 + 4 ) "), Ok(("", 14))); - assert_eq!(expr.parse_peek(" 2*2 / ( 5 - 1) + 3"), Ok(("", 4))); + let input = " ( 2 )"; + let expected = Ok(("", 2)); + assert_eq!(expr.parse_peek(input), expected); + + let input = " 2* ( 3 + 4 ) "; + let expected = Ok(("", 14)); + assert_eq!(expr.parse_peek(input), expected); + + let input = " 2*2 / ( 5 - 1) + 3"; + let expected = Ok(("", 4)); + assert_eq!(expr.parse_peek(input), expected); } diff --git a/vendor/winnow/examples/arithmetic/parser_ast.rs b/vendor/winnow/examples/arithmetic/parser_ast.rs index 5fb9847c0..0ca153487 100644 --- a/vendor/winnow/examples/arithmetic/parser_ast.rs +++ b/vendor/winnow/examples/arithmetic/parser_ast.rs @@ -5,13 +5,14 @@ use std::str::FromStr; use winnow::prelude::*; use winnow::{ - ascii::{digit1 as digit, multispace0 as multispace}, + ascii::{digit1 as digits, multispace0 as multispaces}, combinator::alt, - combinator::repeat, - combinator::{delimited, preceded}, + combinator::delimited, + combinator::fold_repeat, + token::one_of, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Expr { Value(i64), Add(Box<Expr>, Box<Expr>), @@ -21,12 +22,17 @@ pub enum Expr { Paren(Box<Expr>), } -#[derive(Debug)] -pub enum Oper { - Add, - Sub, - Mul, - Div, +impl Expr { + pub fn eval(&self) -> i64 { + match self { + Self::Value(v) => *v, + Self::Add(lhs, rhs) => lhs.eval() + rhs.eval(), + Self::Sub(lhs, rhs) => lhs.eval() - rhs.eval(), + Self::Mul(lhs, rhs) => lhs.eval() * rhs.eval(), + Self::Div(lhs, rhs) => lhs.eval() / rhs.eval(), + Self::Paren(expr) => expr.eval(), + } + } } impl Display for Expr { @@ -44,125 +50,135 @@ impl Display for Expr { } pub fn expr(i: &mut &str) -> PResult<Expr> { - let initial = term(i)?; - let remainder = repeat( + let init = term.parse_next(i)?; + + fold_repeat( 0.., - alt(( - |i: &mut &str| { - let add = preceded("+", term).parse_next(i)?; - Ok((Oper::Add, add)) - }, - |i: &mut &str| { - let sub = preceded("-", term).parse_next(i)?; - Ok((Oper::Sub, sub)) - }, - )), + (one_of(['+', '-']), term), + move || init.clone(), + |acc, (op, val): (char, Expr)| { + if op == '+' { + Expr::Add(Box::new(acc), Box::new(val)) + } else { + Expr::Sub(Box::new(acc), Box::new(val)) + } + }, ) - .parse_next(i)?; - - Ok(fold_exprs(initial, remainder)) + .parse_next(i) } fn term(i: &mut &str) -> PResult<Expr> { - let initial = factor(i)?; - let remainder = repeat( + let init = factor.parse_next(i)?; + + fold_repeat( 0.., - alt(( - |i: &mut &str| { - let mul = preceded("*", factor).parse_next(i)?; - Ok((Oper::Mul, mul)) - }, - |i: &mut &str| { - let div = preceded("/", factor).parse_next(i)?; - Ok((Oper::Div, div)) - }, - )), + (one_of(['*', '/']), factor), + move || init.clone(), + |acc, (op, val): (char, Expr)| { + if op == '*' { + Expr::Mul(Box::new(acc), Box::new(val)) + } else { + Expr::Div(Box::new(acc), Box::new(val)) + } + }, ) - .parse_next(i)?; - - Ok(fold_exprs(initial, remainder)) -} - -fn factor(i: &mut &str) -> PResult<Expr> { - alt(( - delimited(multispace, digit, multispace) - .try_map(FromStr::from_str) - .map(Expr::Value), - parens, - )) .parse_next(i) } -fn parens(i: &mut &str) -> PResult<Expr> { +fn factor(i: &mut &str) -> PResult<Expr> { delimited( - multispace, - delimited("(", expr.map(|e| Expr::Paren(Box::new(e))), ")"), - multispace, + multispaces, + alt((digits.try_map(FromStr::from_str).map(Expr::Value), parens)), + multispaces, ) .parse_next(i) } -fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { - remainder.into_iter().fold(initial, |acc, pair| { - let (oper, expr) = pair; - match oper { - Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)), - Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)), - Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)), - Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)), - } - }) +fn parens(i: &mut &str) -> PResult<Expr> { + delimited("(", expr, ")") + .map(|e| Expr::Paren(Box::new(e))) + .parse_next(i) } #[test] fn factor_test() { - assert_eq!( - factor - .parse_peek(" 3 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(("", String::from("Value(3)"))) - ); + let input = "3"; + let expected = Ok(("", String::from("Value(3)"))); + assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 12"; + let expected = Ok(("", String::from("Value(12)"))); + assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = "537 "; + let expected = Ok(("", String::from("Value(537)"))); + assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 24 "; + let expected = Ok(("", String::from("Value(24)"))); + assert_eq!(factor.map(|e| format!("{e:?}")).parse_peek(input), expected); } #[test] fn term_test() { - assert_eq!( - term.parse_peek(" 3 * 5 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(("", String::from("Mul(Value(3), Value(5))"))) - ); + let input = " 12 *2 / 3"; + let expected = Ok(("", String::from("Div(Mul(Value(12), Value(2)), Value(3))"))); + assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 12 *2 / 3"; + let expected = Ok(("", String::from("Div(Mul(Value(12), Value(2)), Value(3))"))); + assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 2* 3 *2 *2 / 3"; + let expected = Ok(( + "", + String::from("Div(Mul(Mul(Mul(Value(2), Value(3)), Value(2)), Value(2)), Value(3))"), + )); + assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 48 / 3/2"; + let expected = Ok(("", String::from("Div(Div(Value(48), Value(3)), Value(2))"))); + assert_eq!(term.map(|e| format!("{e:?}")).parse_peek(input), expected); } #[test] fn expr_test() { - assert_eq!( - expr.parse_peek(" 1 + 2 * 3 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(("", String::from("Add(Value(1), Mul(Value(2), Value(3)))"))) - ); - assert_eq!( - expr.parse_peek(" 1 + 2 * 3 / 4 - 5 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(( - "", - String::from("Sub(Add(Value(1), Div(Mul(Value(2), Value(3)), Value(4))), Value(5))") - )) - ); - assert_eq!( - expr.parse_peek(" 72 / 2 / 3 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(("", String::from("Div(Div(Value(72), Value(2)), Value(3))"))) - ); + let input = " 1 + 2 "; + let expected = Ok(("", String::from("Add(Value(1), Value(2))"))); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 12 + 6 - 4+ 3"; + let expected = Ok(( + "", + String::from("Add(Sub(Add(Value(12), Value(6)), Value(4)), Value(3))"), + )); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 1 + 2*3 + 4"; + let expected = Ok(( + "", + String::from("Add(Add(Value(1), Mul(Value(2), Value(3))), Value(4))"), + )); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); } #[test] fn parens_test() { - assert_eq!( - expr.parse_peek(" ( 1 + 2 ) * 3 ") - .map(|(i, x)| (i, format!("{:?}", x))), - Ok(( - "", - String::from("Mul(Paren(Add(Value(1), Value(2))), Value(3))") - )) - ); + let input = " ( 2 )"; + let expected = Ok(("", String::from("Paren(Value(2))"))); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 2* ( 3 + 4 ) "; + let expected = Ok(( + "", + String::from("Mul(Value(2), Paren(Add(Value(3), Value(4))))"), + )); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); + + let input = " 2*2 / ( 5 - 1) + 3"; + let expected = Ok(( + "", + String::from("Add(Div(Mul(Value(2), Value(2)), Paren(Sub(Value(5), Value(1)))), Value(3))"), + )); + assert_eq!(expr.map(|e| format!("{e:?}")).parse_peek(input), expected); } diff --git a/vendor/winnow/examples/arithmetic/parser_lexer.rs b/vendor/winnow/examples/arithmetic/parser_lexer.rs new file mode 100644 index 000000000..f49566d38 --- /dev/null +++ b/vendor/winnow/examples/arithmetic/parser_lexer.rs @@ -0,0 +1,297 @@ +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; + +use std::str::FromStr; + +use winnow::prelude::*; +use winnow::{ + ascii::{digit1 as digits, multispace0 as multispaces}, + combinator::alt, + combinator::dispatch, + combinator::fail, + combinator::fold_repeat, + combinator::peek, + combinator::repeat, + combinator::{delimited, preceded, terminated}, + token::any, + token::one_of, +}; + +#[derive(Debug, Clone)] +pub enum Expr { + Value(i64), + Add(Box<Expr>, Box<Expr>), + Sub(Box<Expr>, Box<Expr>), + Mul(Box<Expr>, Box<Expr>), + Div(Box<Expr>, Box<Expr>), + Paren(Box<Expr>), +} + +impl Expr { + pub fn eval(&self) -> i64 { + match self { + Self::Value(v) => *v, + Self::Add(lhs, rhs) => lhs.eval() + rhs.eval(), + Self::Sub(lhs, rhs) => lhs.eval() - rhs.eval(), + Self::Mul(lhs, rhs) => lhs.eval() * rhs.eval(), + Self::Div(lhs, rhs) => lhs.eval() / rhs.eval(), + Self::Paren(expr) => expr.eval(), + } + } +} + +impl Display for Expr { + fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result { + use Expr::{Add, Div, Mul, Paren, Sub, Value}; + match *self { + Value(val) => write!(format, "{}", val), + Add(ref left, ref right) => write!(format, "{} + {}", left, right), + Sub(ref left, ref right) => write!(format, "{} - {}", left, right), + Mul(ref left, ref right) => write!(format, "{} * {}", left, right), + Div(ref left, ref right) => write!(format, "{} / {}", left, right), + Paren(ref expr) => write!(format, "({})", expr), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Token { + Value(i64), + Oper(Oper), + OpenParen, + CloseParen, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Oper { + Add, + Sub, + Mul, + Div, +} + +impl winnow::stream::ContainsToken<Token> for Token { + #[inline(always)] + fn contains_token(&self, token: Token) -> bool { + *self == token + } +} + +impl winnow::stream::ContainsToken<Token> for &'_ [Token] { + #[inline] + fn contains_token(&self, token: Token) -> bool { + self.iter().any(|t| *t == token) + } +} + +impl<const LEN: usize> winnow::stream::ContainsToken<Token> for &'_ [Token; LEN] { + #[inline] + fn contains_token(&self, token: Token) -> bool { + self.iter().any(|t| *t == token) + } +} + +impl<const LEN: usize> winnow::stream::ContainsToken<Token> for [Token; LEN] { + #[inline] + fn contains_token(&self, token: Token) -> bool { + self.iter().any(|t| *t == token) + } +} + +#[allow(dead_code)] +pub fn expr2(i: &mut &str) -> PResult<Expr> { + let tokens = lex.parse_next(i)?; + expr.parse_next(&mut tokens.as_slice()) +} + +pub fn lex(i: &mut &str) -> PResult<Vec<Token>> { + preceded(multispaces, repeat(1.., terminated(token, multispaces))).parse_next(i) +} + +fn token(i: &mut &str) -> PResult<Token> { + dispatch! {peek(any); + '0'..='9' => digits.try_map(FromStr::from_str).map(Token::Value), + '(' => '('.value(Token::OpenParen), + ')' => ')'.value(Token::CloseParen), + '+' => '+'.value(Token::Oper(Oper::Add)), + '-' => '-'.value(Token::Oper(Oper::Sub)), + '*' => '*'.value(Token::Oper(Oper::Mul)), + '/' => '/'.value(Token::Oper(Oper::Div)), + _ => fail, + } + .parse_next(i) +} + +pub fn expr(i: &mut &[Token]) -> PResult<Expr> { + let init = term.parse_next(i)?; + + fold_repeat( + 0.., + ( + one_of([Token::Oper(Oper::Add), Token::Oper(Oper::Sub)]), + term, + ), + move || init.clone(), + |acc, (op, val): (Token, Expr)| { + if op == Token::Oper(Oper::Add) { + Expr::Add(Box::new(acc), Box::new(val)) + } else { + Expr::Sub(Box::new(acc), Box::new(val)) + } + }, + ) + .parse_next(i) +} + +fn term(i: &mut &[Token]) -> PResult<Expr> { + let init = factor.parse_next(i)?; + + fold_repeat( + 0.., + ( + one_of([Token::Oper(Oper::Mul), Token::Oper(Oper::Div)]), + factor, + ), + move || init.clone(), + |acc, (op, val): (Token, Expr)| { + if op == Token::Oper(Oper::Mul) { + Expr::Mul(Box::new(acc), Box::new(val)) + } else { + Expr::Div(Box::new(acc), Box::new(val)) + } + }, + ) + .parse_next(i) +} + +fn factor(i: &mut &[Token]) -> PResult<Expr> { + alt(( + one_of(|t| matches!(t, Token::Value(_))).map(|t| match t { + Token::Value(v) => Expr::Value(v), + _ => unreachable!(), + }), + parens, + )) + .parse_next(i) +} + +fn parens(i: &mut &[Token]) -> PResult<Expr> { + delimited(one_of(Token::OpenParen), expr, one_of(Token::CloseParen)) + .map(|e| Expr::Paren(Box::new(e))) + .parse_next(i) +} + +#[test] +fn lex_test() { + let input = "3"; + let expected = Ok(String::from(r#"("", [Value(3)])"#)); + assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected); + + let input = " 24 "; + let expected = Ok(String::from(r#"("", [Value(24)])"#)); + assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected); + + let input = " 12 *2 / 3"; + let expected = Ok(String::from( + r#"("", [Value(12), Oper(Mul), Value(2), Oper(Div), Value(3)])"#, + )); + assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected); + + let input = " 2*2 / ( 5 - 1) + 3"; + let expected = Ok(String::from( + r#"("", [Value(2), Oper(Mul), Value(2), Oper(Div), OpenParen, Value(5), Oper(Sub), Value(1), CloseParen, Oper(Add), Value(3)])"#, + )); + assert_eq!(lex.parse_peek(input).map(|e| format!("{e:?}")), expected); +} + +#[test] +fn factor_test() { + let input = "3"; + let expected = Ok(String::from("Value(3)")); + let input = lex.parse(input).unwrap(); + assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 12"; + let expected = Ok(String::from("Value(12)")); + let input = lex.parse(input).unwrap(); + assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = "537 "; + let expected = Ok(String::from("Value(537)")); + let input = lex.parse(input).unwrap(); + assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 24 "; + let expected = Ok(String::from("Value(24)")); + let input = lex.parse(input).unwrap(); + assert_eq!(factor.map(|e| format!("{e:?}")).parse(&input), expected); +} + +#[test] +fn term_test() { + let input = " 12 *2 / 3"; + let expected = Ok(String::from("Div(Mul(Value(12), Value(2)), Value(3))")); + let input = lex.parse(input).unwrap(); + assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 12 *2 / 3"; + let expected = Ok(String::from("Div(Mul(Value(12), Value(2)), Value(3))")); + let input = lex.parse(input).unwrap(); + assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 2* 3 *2 *2 / 3"; + let expected = Ok(String::from( + "Div(Mul(Mul(Mul(Value(2), Value(3)), Value(2)), Value(2)), Value(3))", + )); + let input = lex.parse(input).unwrap(); + assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 48 / 3/2"; + let expected = Ok(String::from("Div(Div(Value(48), Value(3)), Value(2))")); + let input = lex.parse(input).unwrap(); + assert_eq!(term.map(|e| format!("{e:?}")).parse(&input), expected); +} + +#[test] +fn expr_test() { + let input = " 1 + 2 "; + let expected = Ok(String::from("Add(Value(1), Value(2))")); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 12 + 6 - 4+ 3"; + let expected = Ok(String::from( + "Add(Sub(Add(Value(12), Value(6)), Value(4)), Value(3))", + )); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 1 + 2*3 + 4"; + let expected = Ok(String::from( + "Add(Add(Value(1), Mul(Value(2), Value(3))), Value(4))", + )); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); +} + +#[test] +fn parens_test() { + let input = " ( 2 )"; + let expected = Ok(String::from("Paren(Value(2))")); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 2* ( 3 + 4 ) "; + let expected = Ok(String::from( + "Mul(Value(2), Paren(Add(Value(3), Value(4))))", + )); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); + + let input = " 2*2 / ( 5 - 1) + 3"; + let expected = Ok(String::from( + "Add(Div(Mul(Value(2), Value(2)), Paren(Sub(Value(5), Value(1)))), Value(3))", + )); + let input = lex.parse(input).unwrap(); + assert_eq!(expr.map(|e| format!("{e:?}")).parse(&input), expected); +} diff --git a/vendor/winnow/examples/http/parser.rs b/vendor/winnow/examples/http/parser.rs index 7f62c4447..3a047545f 100644 --- a/vendor/winnow/examples/http/parser.rs +++ b/vendor/winnow/examples/http/parser.rs @@ -118,7 +118,7 @@ fn is_token(c: u8) -> bool { } fn is_version(c: u8) -> bool { - (b'0'..=b'9').contains(&c) || c == b'.' + c.is_ascii_digit() || c == b'.' } fn not_line_ending(c: u8) -> bool { diff --git a/vendor/winnow/examples/http/parser_streaming.rs b/vendor/winnow/examples/http/parser_streaming.rs index d59e6f8a9..1f850e8b4 100644 --- a/vendor/winnow/examples/http/parser_streaming.rs +++ b/vendor/winnow/examples/http/parser_streaming.rs @@ -119,7 +119,7 @@ fn is_token(c: u8) -> bool { } fn is_version(c: u8) -> bool { - (b'0'..=b'9').contains(&c) || c == b'.' + c.is_ascii_digit() || c == b'.' } fn not_line_ending(c: u8) -> bool { diff --git a/vendor/winnow/examples/ini/parser_str.rs b/vendor/winnow/examples/ini/parser_str.rs index 8f7b9cefc..c1858dbfc 100644 --- a/vendor/winnow/examples/ini/parser_str.rs +++ b/vendor/winnow/examples/ini/parser_str.rs @@ -6,7 +6,7 @@ use winnow::{ combinator::opt, combinator::repeat, combinator::{delimited, terminated}, - token::{take_till0, take_while}, + token::{take_till, take_while}, }; pub type Stream<'i> = &'i str; @@ -36,7 +36,7 @@ fn keys_and_values<'s>(input: &mut Stream<'s>) -> PResult<HashMap<&'s str, &'s s fn key_value<'s>(i: &mut Stream<'s>) -> PResult<(&'s str, &'s str)> { let key = alphanumeric.parse_next(i)?; let _ = (opt(space), "=", opt(space)).parse_next(i)?; - let val = take_till0(is_line_ending_or_comment).parse_next(i)?; + let val = take_till(0.., is_line_ending_or_comment).parse_next(i)?; let _ = opt(space).parse_next(i)?; let _ = opt((";", not_line_ending)).parse_next(i)?; let _ = opt(space_or_line_ending).parse_next(i)?; diff --git a/vendor/winnow/examples/json/parser.rs b/vendor/winnow/examples/json/parser.rs index 8aa3bd387..250621e9c 100644 --- a/vendor/winnow/examples/json/parser.rs +++ b/vendor/winnow/examples/json/parser.rs @@ -7,7 +7,7 @@ use winnow::{ combinator::alt, combinator::cut_err, combinator::{delimited, preceded, separated_pair, terminated}, - combinator::{fold_repeat, separated0}, + combinator::{fold_repeat, separated}, error::{AddContext, ParserError}, token::{any, none_of, take, take_while}, }; @@ -153,7 +153,7 @@ fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<u1 .parse_next(input) } -/// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, +/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly, /// accumulating results in a `Vec`, until it encounters an error. /// If you want more control on the parser application, check out the `iterator` /// combinator (cf `examples/iterator.rs`) @@ -162,7 +162,10 @@ fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>( ) -> PResult<Vec<JsonValue>, E> { preceded( ('[', ws), - cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), + cut_err(terminated( + separated(0.., json_value, (ws, ',', ws)), + (ws, ']'), + )), ) .context("array") .parse_next(input) @@ -173,7 +176,10 @@ fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>> ) -> PResult<HashMap<String, JsonValue>, E> { preceded( ('{', ws), - cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), + cut_err(terminated( + separated(0.., key_value, (ws, ',', ws)), + (ws, '}'), + )), ) .context("object") .parse_next(input) diff --git a/vendor/winnow/examples/json/parser_dispatch.rs b/vendor/winnow/examples/json/parser_dispatch.rs index 6fa722b45..8f7eaf999 100644 --- a/vendor/winnow/examples/json/parser_dispatch.rs +++ b/vendor/winnow/examples/json/parser_dispatch.rs @@ -10,7 +10,7 @@ use winnow::{ combinator::success, combinator::{alt, dispatch}, combinator::{delimited, preceded, separated_pair, terminated}, - combinator::{fold_repeat, separated0}, + combinator::{fold_repeat, separated}, error::{AddContext, ParserError}, token::{any, none_of, take, take_while}, }; @@ -160,7 +160,7 @@ fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<u1 .parse_next(input) } -/// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, +/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly, /// accumulating results in a `Vec`, until it encounters an error. /// If you want more control on the parser application, check out the `iterator` /// combinator (cf `examples/iterator.rs`) @@ -169,7 +169,10 @@ fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>( ) -> PResult<Vec<JsonValue>, E> { preceded( ('[', ws), - cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), + cut_err(terminated( + separated(0.., json_value, (ws, ',', ws)), + (ws, ']'), + )), ) .context("array") .parse_next(input) @@ -180,7 +183,10 @@ fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>> ) -> PResult<HashMap<String, JsonValue>, E> { preceded( ('{', ws), - cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), + cut_err(terminated( + separated(0.., key_value, (ws, ',', ws)), + (ws, '}'), + )), ) .context("object") .parse_next(input) diff --git a/vendor/winnow/examples/json/parser_partial.rs b/vendor/winnow/examples/json/parser_partial.rs index 3538d8e13..779e05f87 100644 --- a/vendor/winnow/examples/json/parser_partial.rs +++ b/vendor/winnow/examples/json/parser_partial.rs @@ -7,7 +7,7 @@ use winnow::{ combinator::alt, combinator::{cut_err, rest}, combinator::{delimited, preceded, separated_pair, terminated}, - combinator::{fold_repeat, separated0}, + combinator::{fold_repeat, separated}, error::{AddContext, ParserError}, stream::Partial, token::{any, none_of, take, take_while}, @@ -154,7 +154,7 @@ fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<u1 .parse_next(input) } -/// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, +/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly, /// accumulating results in a `Vec`, until it encounters an error. /// If you want more control on the parser application, check out the `iterator` /// combinator (cf `examples/iterator.rs`) @@ -163,7 +163,10 @@ fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>( ) -> PResult<Vec<JsonValue>, E> { preceded( ('[', ws), - cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), + cut_err(terminated( + separated(0.., json_value, (ws, ',', ws)), + (ws, ']'), + )), ) .context("array") .parse_next(input) @@ -174,7 +177,10 @@ fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>> ) -> PResult<HashMap<String, JsonValue>, E> { preceded( ('{', ws), - cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), + cut_err(terminated( + separated(0.., key_value, (ws, ',', ws)), + (ws, '}'), + )), ) .context("object") .parse_next(input) diff --git a/vendor/winnow/examples/json_iterator.rs b/vendor/winnow/examples/json_iterator.rs index b8b46f39c..9c21ae38c 100644 --- a/vendor/winnow/examples/json_iterator.rs +++ b/vendor/winnow/examples/json_iterator.rs @@ -5,7 +5,7 @@ use winnow::{ ascii::{alphanumeric1 as alphanumeric, escaped, float}, combinator::alt, combinator::cut_err, - combinator::separated0, + combinator::separated, combinator::{preceded, separated_pair, terminated}, error::ParserError, error::StrContext, @@ -233,7 +233,7 @@ fn array(i: &mut &str) -> PResult<()> { preceded( '[', cut_err(terminated( - separated0(value, preceded(sp, ',')), + separated(0.., value, preceded(sp, ',')), preceded(sp, ']'), )), ) @@ -249,7 +249,7 @@ fn hash(i: &mut &str) -> PResult<()> { preceded( '{', cut_err(terminated( - separated0(key_value, preceded(sp, ',')), + separated(0.., key_value, preceded(sp, ',')), preceded(sp, '}'), )), ) diff --git a/vendor/winnow/examples/ndjson/parser.rs b/vendor/winnow/examples/ndjson/parser.rs index aaa5c9346..81b47459b 100644 --- a/vendor/winnow/examples/ndjson/parser.rs +++ b/vendor/winnow/examples/ndjson/parser.rs @@ -8,7 +8,7 @@ use winnow::{ combinator::alt, combinator::cut_err, combinator::{delimited, preceded, separated_pair, terminated}, - combinator::{fold_repeat, separated0}, + combinator::{fold_repeat, separated}, error::{AddContext, ParserError}, stream::Partial, token::{any, none_of, take, take_while}, @@ -158,7 +158,7 @@ fn u16_hex<'i, E: ParserError<Stream<'i>>>(input: &mut Stream<'i>) -> PResult<u1 .parse_next(input) } -/// Some combinators, like `separated0` or `many0`, will call a parser repeatedly, +/// Some combinators, like `separated` or `repeat`, will call a parser repeatedly, /// accumulating results in a `Vec`, until it encounters an error. /// If you want more control on the parser application, check out the `iterator` /// combinator (cf `examples/iterator.rs`) @@ -167,7 +167,10 @@ fn array<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>>( ) -> PResult<Vec<JsonValue>, E> { preceded( ('[', ws), - cut_err(terminated(separated0(json_value, (ws, ',', ws)), (ws, ']'))), + cut_err(terminated( + separated(0.., json_value, (ws, ',', ws)), + (ws, ']'), + )), ) .context("array") .parse_next(input) @@ -178,7 +181,10 @@ fn object<'i, E: ParserError<Stream<'i>> + AddContext<Stream<'i>, &'static str>> ) -> PResult<HashMap<String, JsonValue>, E> { preceded( ('{', ws), - cut_err(terminated(separated0(key_value, (ws, ',', ws)), (ws, '}'))), + cut_err(terminated( + separated(0.., key_value, (ws, ',', ws)), + (ws, '}'), + )), ) .context("object") .parse_next(input) diff --git a/vendor/winnow/examples/s_expression/parser.rs b/vendor/winnow/examples/s_expression/parser.rs index 919dcf430..c44505342 100644 --- a/vendor/winnow/examples/s_expression/parser.rs +++ b/vendor/winnow/examples/s_expression/parser.rs @@ -58,7 +58,7 @@ pub enum Atom { BuiltIn(BuiltIn), } -/// Now, the most basic type. We define some built-in functions that our lisp has +/// Now, the most basic type. We define some built-in functions that our lisp has #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum BuiltIn { Plus, diff --git a/vendor/winnow/examples/string/parser.rs b/vendor/winnow/examples/string/parser.rs index 6b6345807..01de737b1 100644 --- a/vendor/winnow/examples/string/parser.rs +++ b/vendor/winnow/examples/string/parser.rs @@ -15,7 +15,7 @@ use winnow::combinator::fold_repeat; use winnow::combinator::{delimited, preceded}; use winnow::error::{FromExternalError, ParserError}; use winnow::prelude::*; -use winnow::token::{take_till1, take_while}; +use winnow::token::{take_till, take_while}; /// Parse a string. Use a loop of `parse_fragment` and push all of the fragments /// into an output string. @@ -78,13 +78,13 @@ where /// Parse a non-empty block of text that doesn't include \ or " fn parse_literal<'a, E: ParserError<&'a str>>(input: &mut &'a str) -> PResult<&'a str, E> { - // `take_till1` parses a string of 0 or more characters that aren't one of the + // `take_till` parses a string of 0 or more characters that aren't one of the // given characters. - let not_quote_slash = take_till1(['"', '\\']); + let not_quote_slash = take_till(1.., ['"', '\\']); // `verify` runs a parser, then runs a verification function on the output of // the parser. The verification function accepts the output only if it - // returns true. In this case, we want to ensure that the output of take_till1 + // returns true. In this case, we want to ensure that the output of take_till // is non-empty. not_quote_slash .verify(|s: &str| !s.is_empty()) diff --git a/vendor/winnow/src/_topic/arithmetic.rs b/vendor/winnow/src/_topic/arithmetic.rs index 1a6eddcc4..d94b4fa4b 100644 --- a/vendor/winnow/src/_topic/arithmetic.rs +++ b/vendor/winnow/src/_topic/arithmetic.rs @@ -11,3 +11,9 @@ //! ```rust #![doc = include_str!("../../examples/arithmetic/parser_ast.rs")] //! ``` +//! +//! ## Parse to Tokens then AST +//! +//! ```rust +#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")] +//! ``` diff --git a/vendor/winnow/src/_topic/mod.rs b/vendor/winnow/src/_topic/mod.rs index 72c8145fe..79ba28a62 100644 --- a/vendor/winnow/src/_topic/mod.rs +++ b/vendor/winnow/src/_topic/mod.rs @@ -14,13 +14,14 @@ //! - [Implementing `FromStr`][fromstr] //! - [Performance][performance] //! - [Parsing Partial Input][partial] -//! - [Custom stream][stream] +//! - [Custom stream or token][stream] //! - [Custom errors][error] //! //! See also parsers written with `winnow`: //! //! - [`toml_edit`](https://crates.io/crates/toml_edit) //! - [`hcl-edit`](https://crates.io/crates/hcl-edit) +#![allow(clippy::std_instead_of_core)] pub mod arithmetic; pub mod error; diff --git a/vendor/winnow/src/_topic/partial.rs b/vendor/winnow/src/_topic/partial.rs index 19895d35a..7a974217e 100644 --- a/vendor/winnow/src/_topic/partial.rs +++ b/vendor/winnow/src/_topic/partial.rs @@ -1,12 +1,12 @@ //! # Parsing Partial Input //! -//! Typically, the input being parsed is all in-memory, or is complete. Some data sources are too +//! Typically, the input being parsed is all in-memory, or is complete. Some data sources are too //! large to fit into memory, only allowing parsing an incomplete or [`Partial`] subset of the //! data, requiring incrementally parsing. //! //! By wrapping a stream, like `&[u8]`, with [`Partial`], parsers will report when the data is //! [`Incomplete`] and more input is [`Needed`], allowing the caller to stream-in additional data -//! to be parsed. The data is then parsed a chunk at a time. +//! to be parsed. The data is then parsed a chunk at a time. //! //! Chunks are typically defined by either: //! - A header reporting the number of bytes, like with [`length_value`] @@ -19,7 +19,7 @@ //! parser is for the next chunk. //! //! Caveats: -//! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to +//! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to //! prevent the re-parsing overhead from dominating. //! - Parsers like [`repeat`] do not know when an `eof` is from insufficient data or the end of the //! stream, causing them to always report [`Incomplete`]. diff --git a/vendor/winnow/src/_topic/performance.rs b/vendor/winnow/src/_topic/performance.rs index 8a6555a06..2b5303846 100644 --- a/vendor/winnow/src/_topic/performance.rs +++ b/vendor/winnow/src/_topic/performance.rs @@ -5,19 +5,19 @@ //! See also the general Rust [Performance Book](https://nnethercote.github.io/perf-book/) //! //! Tips -//! - Try `cargo add winnow -F simd`. For some it offers significant performance improvements +//! - Try `cargo add winnow -F simd`. For some it offers significant performance improvements //! - When enough cases of an [`alt`] have unique prefixes, prefer [`dispatch`] //! - When parsing text, try to parse as bytes (`u8`) rather than `char`s ([`BStr`] can make //! debugging easier) //! - Find simplified subsets of the grammar to parse, falling back to the full grammar when it //! doesn't work. For example, when parsing json strings, parse them without support for escapes, //! falling back to escape support if it fails. -//! - Watch for large return types. A surprising place these can show up is when chaining parsers +//! - Watch for large return types. A surprising place these can show up is when chaining parsers //! with a tuple. //! //! ## Build-time Performance //! -//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in +//! Returning complex types as `impl Trait` can negatively impact build times. This can hit in //! surprising cases like: //! ```rust //! # use winnow::prelude::*; diff --git a/vendor/winnow/src/_topic/stream.rs b/vendor/winnow/src/_topic/stream.rs index 4f94a94b9..2254f8710 100644 --- a/vendor/winnow/src/_topic/stream.rs +++ b/vendor/winnow/src/_topic/stream.rs @@ -1,20 +1,21 @@ -//! # Custom [`Stream`][crate::stream::Stream] +//! # Custom [`Stream`] //! //! `winnow` is batteries included with support for //! - Basic inputs like `&str`, newtypes with -//! - Improved debug output like [`Bytes`][crate::Bytes] -//! - [`Stateful`][crate::Stateful] for passing state through your parser, like tracking recursion +//! - Improved debug output like [`Bytes`] +//! - [`Stateful`] for passing state through your parser, like tracking recursion //! depth -//! - [`Located`][crate::Located] for looking up the absolute position of a token +//! - [`Located`] for looking up the absolute position of a token //! -//! But that won't always cut it for your parser. For example, you might lex `&str` into +//! But that won't always cut it for your parser. For example, you might lex `&str` into //! a series of tokens and then want to parse a `TokenStream`. //! //! ## Implementing a custom stream //! -//! Let's assume we have an input type we'll call `MyStream`. `MyStream` is a sequence of `MyItem` type. -//! The goal is to define parsers with this signature: `&mut MyStream -> PResult<Output>`. +//! Let's assume we have an input type we'll call `MyStream`. +//! `MyStream` is a sequence of `MyItem` type. //! +//! The goal is to define parsers with this signature: `&mut MyStream -> PResult<Output>`. //! ```rust //! # use winnow::prelude::*; //! # use winnow::token::tag; @@ -25,7 +26,7 @@ //! } //! ``` //! -//! Here are the traits we have to implement for `MyStream`: +//! Here are the traits you may have to implement for `MyStream`: //! //! | trait | usage | //! |---|---| @@ -38,17 +39,28 @@ //! | [`Location`] |Calculate location within initial input| //! | [`Offset`] |Calculate the offset between slices| //! -//! Here are the traits we have to implement for `MyItem`: +//! And for `MyItem`: //! //! | trait | usage | //! |---|---| //! | [`AsChar`] |Transforms common types to a char for basic token parsing| //! | [`ContainsToken`] |Look for the token in the given set| //! -//! And traits for slices of `MyItem`: +//! And traits for `&[MyItem]`: //! +//! | trait | usage | +//! |---|---| //! | [`SliceLen`] |Calculate the input length| //! | [`ParseSlice`] |Used to integrate `&str`'s `parse()` method| +//! +//! ## Implementing a custom token +//! +//! If you are parsing `&[Myitem]`, leaving just the `MyItem` traits. +//! +//! For example: +//! ```rust +#![doc = include_str!("../../examples/arithmetic/parser_lexer.rs")] +//! ``` #[allow(unused_imports)] // Here for intra-dock links use crate::stream::*; diff --git a/vendor/winnow/src/_topic/why.rs b/vendor/winnow/src/_topic/why.rs index e0328f117..d49af7e01 100644 --- a/vendor/winnow/src/_topic/why.rs +++ b/vendor/winnow/src/_topic/why.rs @@ -2,7 +2,7 @@ //! //! To answer this question, it will be useful to contrast this with other approaches to parsing. //! -//! **Note:** This will focus on principles and priorities. For a deeper and wider wider +//! **Note:** This will focus on principles and priorities. For a deeper and wider wider //! comparison with other Rust parser libraries, see //! [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs). //! @@ -58,7 +58,7 @@ //! //! ## `nom` //! -//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference +//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference //! between them is largely in priorities. `nom` prioritizes: //! - Lower churn for existing users while `winnow` is trying to find ways to make things better //! for the parsers yet to be written. @@ -78,10 +78,10 @@ //! > "If you need to implement either `Parser` or `Strategy` by hand, that's a problem that needs fixing". //! //! This is under "batteries included" but it also ties into the feeling that `chumksy` acts more like -//! a framework. Instead of composing together helpers, you are expected to do everything through +//! a framework. Instead of composing together helpers, you are expected to do everything through //! their system to the point that it is non-trivial to implement their `Parser` trait and are //! encouraged to use the -//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This +//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This //! requires re-framing everything to fit within their model and makes the code harder to understand //! and debug as you are working with abstract operations that will eventually be applied //! rather than directly with the parsers. @@ -90,7 +90,7 @@ //! Probably the biggest thing that `winnow` loses out on is optimizations from ["parse modes" via //! GATs](https://github.com/zesterer/chumsky/pull/82) which allows downstream parsers to tell //! upstream parsers when information will be discarded, allowing bypassing expensive operations, -//! like allocations. This requires a lot more complex interaction with parsers that isn't as +//! like allocations. This requires a lot more complex interaction with parsers that isn't as //! trivial to do with bare functions which would lose out on any of that side-band information. //! Instead, we work around this with things like the [`Accumulate`] trait. diff --git a/vendor/winnow/src/_tutorial/chapter_0.rs b/vendor/winnow/src/_tutorial/chapter_0.rs index 47c196e86..35a2d1476 100644 --- a/vendor/winnow/src/_tutorial/chapter_0.rs +++ b/vendor/winnow/src/_tutorial/chapter_0.rs @@ -10,7 +10,7 @@ //! ## About //! //! `winnow` is a parser-combinator library. In other words, it gives you tools to define: -//! - "parsers", or functions that takes an input and gives back an output +//! - "parsers", or functions that take an input and give back an output //! - "combinators", or functions that take parsers and _combine_ them together! //! //! While "combinator" might be an unfamiliar word, you are likely using them in your rust code diff --git a/vendor/winnow/src/_tutorial/chapter_1.rs b/vendor/winnow/src/_tutorial/chapter_1.rs index b16a16657..2d94418a9 100644 --- a/vendor/winnow/src/_tutorial/chapter_1.rs +++ b/vendor/winnow/src/_tutorial/chapter_1.rs @@ -10,17 +10,17 @@ //! - `Err` indicates the parser could not find what it was looking for. //! //! Parsers do more than just return a binary "success"/"failure" code. -//! On success, the parser will return the processed data. The input will be left pointing to +//! On success, the parser will return the processed data. The input will be left pointing to //! data that still needs processing //! //! If the parser failed, then there are multiple errors that could be returned. //! For simplicity, however, in the next chapters we will leave these unexplored. //! //! ```text -//! ┌─► Ok(what matched the parser) -//! ┌─────────┐ │ -//! my input───►│my parser├──►either──┤ -//! └─────────┘ └─► Err(...) +//! ┌─► Ok(what matched the parser) +//! ┌─────────┐ │ +//! my input───►│my parser├──►either──┤ +//! └─────────┘ └─► Err(...) //! ``` //! //! @@ -53,7 +53,7 @@ //! //! This parser function should take in a `&str`: //! -//! - Since it is supposed to succeed, we know it will return the Ok Variant. +//! - Since it is supposed to succeed, we know it will return the `Ok` variant. //! - Since it does nothing to our input, the remaining input is the same as the input. //! - Since it doesn't parse anything, it also should just return an empty string. //! diff --git a/vendor/winnow/src/_tutorial/chapter_2.rs b/vendor/winnow/src/_tutorial/chapter_2.rs index 0fb80ac37..c27b7196e 100644 --- a/vendor/winnow/src/_tutorial/chapter_2.rs +++ b/vendor/winnow/src/_tutorial/chapter_2.rs @@ -4,7 +4,7 @@ //! //! ## Tokens //! -//! [`Stream`] provides some core operations to help with parsing. For example, to process a +//! [`Stream`] provides some core operations to help with parsing. For example, to process a //! single token, you can do: //! ```rust //! # use winnow::Parser; @@ -135,13 +135,13 @@ //! # } //! ``` //! -//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual +//! In `winnow`, we call this type of parser a [`tag`]. See [`token`] for additional individual //! and token-slice parsers. //! //! ## Character Classes //! -//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several -//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parer: +//! Selecting a single `char` or a [`tag`] is fairly limited. Sometimes, you will want to select one of several +//! `chars` of a specific class, like digits. For this, we use the [`one_of`] parser: //! //! ```rust //! # use winnow::Parser; @@ -207,7 +207,7 @@ //! } //! ``` //! -//! We could simplify this further with by using one of the built-in character classes, [`hex_digit1`]: +//! We could simplify this further by using one of the built-in character classes, [`hex_digit1`]: //! ```rust //! # use winnow::Parser; //! # use winnow::PResult; diff --git a/vendor/winnow/src/_tutorial/chapter_3.rs b/vendor/winnow/src/_tutorial/chapter_3.rs index 4dfdc31e4..e3f86b501 100644 --- a/vendor/winnow/src/_tutorial/chapter_3.rs +++ b/vendor/winnow/src/_tutorial/chapter_3.rs @@ -179,7 +179,7 @@ //! ``` //! //! > **Warning:** the above example is for illustrative purposes and relying on `Result::Ok` or -//! > `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering +//! > `Result::Err` can lead to incorrect behavior. This will be clarified in later when covering //! > [error handling][`chapter_6`#errmode] //! //! [`opt`] is a basic building block for correctly handling retrying parsing: @@ -296,8 +296,8 @@ //! > **Note:** [`success`] and [`fail`] are parsers that might be useful in the `else` case. //! //! Sometimes a giant if/else-if ladder can be slow and you'd rather have a `match` statement for -//! branches of your parser that have unique prefixes. In this case, you can use the -//! [`dispatch`][crate::combinator::dispatch] macro: +//! branches of your parser that have unique prefixes. In this case, you can use the +//! [`dispatch`] macro: //! //! ```rust //! # use winnow::prelude::*; diff --git a/vendor/winnow/src/_tutorial/chapter_4.rs b/vendor/winnow/src/_tutorial/chapter_4.rs index 59aa7ee87..328a64843 100644 --- a/vendor/winnow/src/_tutorial/chapter_4.rs +++ b/vendor/winnow/src/_tutorial/chapter_4.rs @@ -10,9 +10,6 @@ //! All we need to do for our parser to return a different type is to change //! the type parameter of [`PResult`] to the desired return type. //! For example, to return a `usize`, return a `PResult<usize>`. -//! Recall that the type parameter of the `PResult` is the input -//! type, so even if you're returning something different, if your input -//! is a `&str`, the type argument of `PResult` should be also. //! //! One winnow-native way of doing a type conversion is to use the //! [`Parser::parse_to`] combinator diff --git a/vendor/winnow/src/_tutorial/chapter_5.rs b/vendor/winnow/src/_tutorial/chapter_5.rs index ffd8a29ce..8aa719b98 100644 --- a/vendor/winnow/src/_tutorial/chapter_5.rs +++ b/vendor/winnow/src/_tutorial/chapter_5.rs @@ -136,18 +136,18 @@ //! # } //! ``` //! -//! You'll notice that the above allows trailing `,` when we intended to not support that. We can -//! easily fix this by using [`separated0`]: +//! You'll notice that the above allows trailing `,` when we intended to not support that. We can +//! easily fix this by using [`separated`]: //! ```rust //! # use winnow::prelude::*; //! # use winnow::token::take_while; //! # use winnow::combinator::dispatch; //! # use winnow::token::take; //! # use winnow::combinator::fail; -//! use winnow::combinator::separated0; +//! use winnow::combinator::separated; //! //! fn parse_list(input: &mut &str) -> PResult<Vec<usize>> { -//! separated0(parse_digits, ",").parse_next(input) +//! separated(0.., parse_digits, ",").parse_next(input) //! } //! //! // ... @@ -200,7 +200,7 @@ //! ``` //! //! If you look closely at [`repeat`], it isn't collecting directly into a [`Vec`] but -//! [`Accumulate`] to gather the results. This let's us make more complex parsers than we did in +//! [`Accumulate`] to gather the results. This lets us make more complex parsers than we did in //! [`chapter_2`] by accumulating the results into a `()` and [`recognize`][Parser::recognize]-ing the captured input: //! ```rust //! # use winnow::prelude::*; @@ -208,14 +208,14 @@ //! # use winnow::combinator::dispatch; //! # use winnow::token::take; //! # use winnow::combinator::fail; -//! # use winnow::combinator::separated0; +//! # use winnow::combinator::separated; //! # //! fn recognize_list<'s>(input: &mut &'s str) -> PResult<&'s str> { //! parse_list.recognize().parse_next(input) //! } //! //! fn parse_list(input: &mut &str) -> PResult<()> { -//! separated0(parse_digits, ",").parse_next(input) +//! separated(0.., parse_digits, ",").parse_next(input) //! } //! //! # fn parse_digits(input: &mut &str) -> PResult<usize> { @@ -272,7 +272,7 @@ use super::chapter_2; use super::chapter_3; use crate::combinator; use crate::combinator::repeat; -use crate::combinator::separated0; +use crate::combinator::separated; use crate::stream::Accumulate; use crate::Parser; use std::vec::Vec; diff --git a/vendor/winnow/src/_tutorial/chapter_6.rs b/vendor/winnow/src/_tutorial/chapter_6.rs index 9f4230942..0d54e1505 100644 --- a/vendor/winnow/src/_tutorial/chapter_6.rs +++ b/vendor/winnow/src/_tutorial/chapter_6.rs @@ -72,13 +72,13 @@ //! ```rust //! # use winnow::error::ErrorKind; //! # use winnow::error::ErrMode; -//! pub type OResult<O, E = ErrorKind> = Result<O, ErrMode<E>>; +//! pub type PResult<O, E = ErrorKind> = Result<O, ErrMode<E>>; //! ``` //! [`PResult`] is just a fancy wrapper around `Result` that wraps our error in an [`ErrMode`] //! type. //! //! [`ErrMode`] is an enum with [`Backtrack`] and [`Cut`] variants (ignore [`Incomplete`] as its only -//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that +//! relevant for [streaming][_topic::stream]). By default, errors are [`Backtrack`], meaning that //! other parsing branches will be attempted on failure, like the next case of an [`alt`]. [`Cut`] //! shortcircuits all other branches, immediately reporting the error. //! diff --git a/vendor/winnow/src/_tutorial/mod.rs b/vendor/winnow/src/_tutorial/mod.rs index 224fe6a80..2a4bd61f7 100644 --- a/vendor/winnow/src/_tutorial/mod.rs +++ b/vendor/winnow/src/_tutorial/mod.rs @@ -1,6 +1,7 @@ //! # Tutorial //! //! Table of Contents +#![allow(clippy::std_instead_of_core)] pub mod chapter_0; pub mod chapter_1; diff --git a/vendor/winnow/src/ascii/mod.rs b/vendor/winnow/src/ascii/mod.rs index 8b3119fbf..6221efc2d 100644 --- a/vendor/winnow/src/ascii/mod.rs +++ b/vendor/winnow/src/ascii/mod.rs @@ -15,12 +15,41 @@ use crate::error::{ErrMode, ErrorKind, Needed}; use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial}; use crate::stream::{Compare, CompareResult}; use crate::token::one_of; -use crate::token::take_till0; +use crate::token::take_till; use crate::token::take_while; use crate::trace::trace; use crate::PResult; use crate::Parser; +/// Mark a value as case-insensitive for ASCII characters +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}}; +/// # use winnow::ascii::Caseless; +/// +/// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> { +/// Caseless("hello").parse_next(s) +/// } +/// +/// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello"))); +/// assert_eq!(parser.parse_peek("HeLlo, World!"), Ok((", World!", "HeLlo"))); +/// assert_eq!(parser.parse_peek("Some"), Err(ErrMode::Backtrack(InputError::new("Some", ErrorKind::Tag)))); +/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag)))); +/// ``` +#[derive(Copy, Clone, Debug)] +pub struct Caseless<T>(pub T); + +impl Caseless<&str> { + /// Get the byte-representation of this case-insensitive value + #[inline(always)] + pub fn as_bytes(&self) -> Caseless<&[u8]> { + Caseless(self.0.as_bytes()) + } +} + /// Recognizes the string `"\r\n"`. /// /// *Complete version*: Will return an error if there's not enough input data. @@ -123,7 +152,7 @@ where I: Compare<&'static str>, <I as Stream>::Token: AsChar + Clone, { - let res = take_till0(('\r', '\n')).parse_next(input)?; + let res = take_till(0.., ('\r', '\n')).parse_next(input)?; if input.compare("\r") == CompareResult::Ok { let comp = input.compare("\r\n"); match comp { @@ -423,7 +452,7 @@ where /// /// ## Parsing an integer /// -/// You can use `digit1` in combination with [`Parser::try_map`][crate::Parser::try_map] to parse an integer: +/// You can use `digit1` in combination with [`Parser::try_map`] to parse an integer: /// /// ``` /// # use winnow::prelude::*; @@ -965,6 +994,7 @@ impl Uint for u128 { } } +/// Deprecated since v0.15.17 impl Uint for i8 { fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> { self.checked_mul(by as Self) @@ -974,6 +1004,7 @@ impl Uint for i8 { } } +/// Deprecated since v0.15.17 impl Uint for i16 { fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> { self.checked_mul(by as Self) @@ -983,6 +1014,7 @@ impl Uint for i16 { } } +/// Deprecated since v0.15.17 impl Uint for i32 { fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> { self.checked_mul(by as Self) @@ -992,6 +1024,7 @@ impl Uint for i32 { } } +/// Deprecated since v0.15.17 impl Uint for i64 { fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> { self.checked_mul(by as Self) @@ -1001,6 +1034,7 @@ impl Uint for i64 { } } +/// Deprecated since v0.15.17 impl Uint for i128 { fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option<Self> { self.checked_mul(by as Self) @@ -1318,6 +1352,7 @@ where } #[allow(clippy::trait_duplication_in_bounds)] // HACK: clippy 1.64.0 bug +#[allow(deprecated)] fn recognize_float_or_exceptions<I, E: ParserError<I>>( input: &mut I, ) -> PResult<<I as Stream>::Slice, E> diff --git a/vendor/winnow/src/binary/bits/mod.rs b/vendor/winnow/src/binary/bits/mod.rs index b11ba43c7..16a0f6464 100644 --- a/vendor/winnow/src/binary/bits/mod.rs +++ b/vendor/winnow/src/binary/bits/mod.rs @@ -157,7 +157,7 @@ where /// } /// /// fn parser(input: (Stream<'_>, usize), count: usize)-> IResult<(Stream<'_>, usize), u8> { -/// take(count).parse_peek(input) +/// take(count).parse_peek(input) /// } /// /// // Consumes 0 bits, returns 0 diff --git a/vendor/winnow/src/combinator/core.rs b/vendor/winnow/src/combinator/core.rs index d784b4e9e..2a92d64b7 100644 --- a/vendor/winnow/src/combinator/core.rs +++ b/vendor/winnow/src/combinator/core.rs @@ -331,7 +331,7 @@ where /// Call the iterator's [`ParserIterator::finish`] method to get the remaining input if successful, /// or the error value if we encountered an error. /// -/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`]. +/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`]. /// /// # Example /// diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs index ec68e48e2..542b156a2 100644 --- a/vendor/winnow/src/combinator/mod.rs +++ b/vendor/winnow/src/combinator/mod.rs @@ -6,72 +6,71 @@ //! //! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer". //! -//! | combinator | usage | input | output | comment | -//! |---|---|---|---|---| -//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)| -//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `Ok(("yab", 'x'))` |Matches anything but the provided characters| -//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `Ok((" world", "hello"))` |Recognizes a specific suite of characters or bytes| -//! | [`tag_no_case`][crate::token::tag_no_case] | `tag_no_case("hello")` | `"HeLLo World"` | `Ok((" World", "HeLLo"))` |Case insensitive comparison. Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises| -//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `Ok(("o", "hell"))` |Takes a specific number of bytes or characters| -//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `Ok(("123", "abc"))` |Returns the longest list of bytes for which the provided pattern matches.| -//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `Ok(("abc", "123"))` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`| -//! | [`take_until0`][crate::token::take_until0] | `take_until0("world")` | `"Hello world"` | `Ok(("world", "Hello "))` |Returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character| +//! | combinator | usage | input | new input | output | comment | +//! |---|---|---|---|---|---| +//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `"bc"` | `Ok('a')` |Matches one of the provided characters (works with non ASCII characters too)| +//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `"yab"` | `Ok('x')` |Matches anything but the provided characters| +//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `" world"` | `Ok("hello")` |Recognizes a specific suite of characters or bytes (see also [`Caseless`][crate::ascii::Caseless])| +//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `"o"` | `Ok("hell")` |Takes a specific number of bytes or characters| +//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `"123"` | `Ok("abc")` |Returns the longest list of bytes for which the provided pattern matches.| +//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `"abc"` | `Ok("123")` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`| +//! | [`take_until0`][crate::token::take_until0] | `take_until0("world")` | `"Hello world"` | `"world"` | `Ok("Hello ")` |Returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character| //! //! ## Choice combinators //! -//! | combinator | usage | input | output | comment | -//! |---|---|---|---|---| -//! | [`alt`][crate::combinator::alt] | `alt(("ab", "cd"))` | `"cdef"` | `Ok(("ef", "cd"))` |Try a list of parsers and return the result of the first successful one| -//! | [`dispatch`][crate::combinator::dispatch] | \- | \- | \- | `match` for parsers | -//! | [`permutation`][crate::combinator::permutation] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `Ok(("c", ("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order| +//! | combinator | usage | input | new input | output | comment | +//! |---|---|---|---|---|---| +//! | [`alt`] | `alt(("ab", "cd"))` | `"cdef"` | `"ef"` | `Ok("cd")` |Try a list of parsers and return the result of the first successful one| +//! | [`dispatch`] | \- | \- | \- | \- | `match` for parsers | +//! | [`permutation`] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `"c"` | `Ok(("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order| //! //! ## Sequence combinators //! -//! | combinator | usage | input | output | comment | -//! |---|---|---|---|---| -//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `Ok(("!", ("ab", "XY", "Z")))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple| -//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `Ok(("cd", "ab"))` || -//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "XY"))` || -//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "ab"))` || -//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `Ok(("!", ("hello", "world")))` || +//! | combinator | usage | input | new input | output | comment | +//! |---|---|---|---|---|---| +//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `"!"` | `Ok(("ab", "XY", "Z"))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple| +//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `"cd"` | `Ok("ab")` || +//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("XY")` || +//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("ab")` || +//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `"!"` | `Ok(("hello", "world"))` || //! //! ## Applying a parser multiple times //! -//! | combinator | usage | input | output | comment | -//! |---|---|---|---|---| -//! | [`repeat`][crate::combinator::repeat] | `repeat(1..=3, "ab")` | `"ababc"` | `Ok(("c", vec!["ab", "ab"]))` |Applies the parser between m and n times (n included) and returns the list of results in a Vec| -//! | [`repeat_till0`][crate::combinator::repeat_till0] | `repeat_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `Ok(("g", (vec!["ab", "ab"], "ef")))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second| -//! | [`separated0`][crate::combinator::separated0] | `separated0("ab", ",")` | `"ab,ab,ab."` | `Ok((".", vec!["ab", "ab", "ab"]))` |`separated1` works like `separated0` but must returns at least one element| -//! | [`fold_repeat`][crate::combinator::fold_repeat] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `Ok(([3], 3))` |Applies the parser between m and n times (n included) and folds the list of return value| +//! | combinator | usage | input | new input | output | comment | +//! |---|---|---|---|---|---| +//! | [`repeat`] | `repeat(1..=3, "ab")` | `"ababc"` | `"c"` | `Ok(vec!["ab", "ab"])` |Applies the parser between m and n times (n included) and returns the list of results in a Vec| +//! | [`repeat_till0`] | `repeat_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `"g"` | `Ok((vec!["ab", "ab"], "ef"))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second| +//! | [`separated`] | `separated(1..=3, "ab", ",")` | `"ab,ab,ab."` | `"."` | `Ok(vec!["ab", "ab", "ab"])` |Applies the parser and separator between m and n times (n included) and returns the list of results in a Vec| +//! | [`fold_repeat`] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `[3]` | `Ok(3)` |Applies the parser between m and n times (n included) and folds the list of return value| //! //! ## Partial related //! -//! - [`eof`][eof]: Returns its input if it is at the end of input data +//! - [`eof`]: Returns its input if it is at the end of input data //! - [`Parser::complete_err`]: Replaces an `Incomplete` returned by the child parser with an `Backtrack` //! //! ## Modifiers //! -//! - [`cond`][cond]: Conditional combinator. Wraps another parser and calls it if the condition is met -//! - [`Parser::flat_map`][crate::Parser::flat_map]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input -//! - [`Parser::value`][crate::Parser::value]: method to replace the result of a parser -//! - [`Parser::map`][crate::Parser::map]: method to map a function on the result of a parser -//! - [`Parser::and_then`][crate::Parser::and_then]: Applies a second parser over the output of the first one -//! - [`Parser::verify_map`][Parser::verify_map]: Maps a function returning an `Option` on the output of a parser -//! - [`Parser::try_map`][Parser::try_map]: Maps a function returning a `Result` on the output of a parser -//! - [`Parser::parse_to`][crate::Parser::parse_to]: Apply [`std::str::FromStr`] to the output of the parser -//! - [`not`][not]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input -//! - [`opt`][opt]: Make the underlying parser optional -//! - [`peek`][peek]: Returns a result without consuming the input -//! - [`Parser::recognize`][Parser::recognize]: If the child parser was successful, return the consumed input as the produced value -//! - [`Parser::with_recognized`][Parser::with_recognized]: If the child parser was successful, return a tuple of the consumed input and the produced output. -//! - [`Parser::span`][Parser::span]: If the child parser was successful, return the location of the consumed input as the produced value -//! - [`Parser::with_span`][Parser::with_span]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output. +//! - [`cond`]: Conditional combinator. Wraps another parser and calls it if the condition is met +//! - [`Parser::flat_map`]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input +//! - [`Parser::value`]: method to replace the result of a parser +//! - [`Parser::map`]: method to map a function on the result of a parser +//! - [`Parser::and_then`]: Applies a second parser over the output of the first one +//! - [`Parser::verify_map`]: Maps a function returning an `Option` on the output of a parser +//! - [`Parser::try_map`]: Maps a function returning a `Result` on the output of a parser +//! - [`Parser::parse_to`]: Apply [`std::str::FromStr`] to the output of the parser +//! - [`not`]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input +//! - [`opt`]: Make the underlying parser optional +//! - [`peek`]: Returns a result without consuming the input +//! - [`Parser::recognize`]: If the child parser was successful, return the consumed input as the produced value +//! - [`Parser::with_recognized`]: If the child parser was successful, return a tuple of the consumed input and the produced output. +//! - [`Parser::span`]: If the child parser was successful, return the location of the consumed input as the produced value +//! - [`Parser::with_span`]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output. //! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function //! //! ## Error management and debugging //! //! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted -//! - [`backtrack_err`]: Attemmpts a parse, allowing alternative parsers to be attempted despite +//! - [`backtrack_err`]: Attempts a parse, allowing alternative parsers to be attempted despite //! use of `cut_err` //! - [`Parser::context`]: Add context to the error if the parser fails //! - [`trace`][crate::trace::trace]: Print the parse state with the `debug` feature flag @@ -79,8 +78,8 @@ //! //! ## Remaining combinators //! -//! - [`success`][success]: Returns a value without consuming any input, always succeeds -//! - [`fail`][fail]: Inversion of `success`. Always fails. +//! - [`success`]: Returns a value without consuming any input, always succeeds +//! - [`fail`]: Inversion of `success`. Always fails. //! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers //! //! ## Text parsing @@ -91,7 +90,7 @@ //! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`) //! - [`newline`][crate::ascii::newline]: Matches a newline character `\n` //! - [`not_line_ending`][crate::ascii::not_line_ending]: Recognizes a string of any char except `\r` or `\n` -//! - [`rest`][rest]: Return the remaining input +//! - [`rest`]: Return the remaining input //! //! - [`alpha0`][crate::ascii::alpha0]: Recognizes zero or more lowercase and uppercase alphabetic characters: `[a-zA-Z]`. [`alpha1`][crate::ascii::alpha1] does the same but returns at least one character //! - [`alphanumeric0`][crate::ascii::alphanumeric0]: Recognizes zero or more numerical and alphabetic characters: `[0-9a-zA-Z]`. [`alphanumeric1`][crate::ascii::alphanumeric1] does the same but returns at least one character diff --git a/vendor/winnow/src/combinator/multi.rs b/vendor/winnow/src/combinator/multi.rs index 1fdb7535b..d06362878 100644 --- a/vendor/winnow/src/combinator/multi.rs +++ b/vendor/winnow/src/combinator/multi.rs @@ -12,7 +12,7 @@ use crate::Parser; /// [`Accumulate`] the output of a parser into a container, like `Vec` /// -/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Arguments @@ -28,7 +28,7 @@ use crate::Parser; /// /// # Example /// -/// Zero or more reptitions: +/// Zero or more repetitions: /// ```rust /// # #[cfg(feature = "std")] { /// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; @@ -47,7 +47,7 @@ use crate::Parser; /// # } /// ``` /// -/// One or more reptitions: +/// One or more repetitions: /// ```rust /// # #[cfg(feature = "std")] { /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; @@ -66,7 +66,7 @@ use crate::Parser; /// # } /// ``` /// -/// Fixed number of repeitions: +/// Fixed number of repetitions: /// ```rust /// # #[cfg(feature = "std")] { /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; @@ -86,7 +86,7 @@ use crate::Parser; /// # } /// ``` /// -/// Arbitrary reptitions: +/// Arbitrary repetitions: /// ```rust /// # #[cfg(feature = "std")] { /// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; @@ -201,6 +201,73 @@ where } } +fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + F: Parser<I, O, E>, + E: ParserError<I>, +{ + let mut res = C::initial(Some(count)); + + for _ in 0..count { + match f.parse_next(i) { + Ok(o) => { + res.accumulate(o); + } + Err(e) => { + return Err(e.append(i, ErrorKind::Many)); + } + } + } + + Ok(res) +} + +fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + F: Parser<I, O, E>, + E: ParserError<I>, +{ + if min > max { + return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); + } + + let mut res = C::initial(Some(min)); + for count in 0..max { + let start = input.checkpoint(); + let len = input.eof_offset(); + match parse.parse_next(input) { + Ok(value) => { + // infinite loop check: the parser must always consume + if input.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`repeat` parsers must always consume", + )); + } + + res.accumulate(value); + } + Err(ErrMode::Backtrack(e)) => { + if count < min { + return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); + } else { + input.reset(start); + return Ok(res); + } + } + Err(e) => { + return Err(e); + } + } + } + + Ok(res) +} + /// [`Accumulate`] the output of parser `f` into a container, like `Vec`, until the parser `g` /// produces a result. /// @@ -269,9 +336,144 @@ where }) } -/// [`Accumulate`] the output of a parser, interleaed with `sep` +/// [`Accumulate`] the output of a parser, interleaved with `sep` /// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// [`cut_err`][crate::combinator::cut_err]. +/// +/// # Arguments +/// * `range` The minimum and maximum number of iterations. +/// * `parser` The parser that parses the elements of the list. +/// * `sep` The parser that parses the separator between list elements. +/// +/// **Warning:** If the separator parser accepts empty inputs +/// (like `alpha0` or `digit0`), `separated` will return an error, +/// to prevent going into an infinite loop. +/// +/// # Example +/// +/// Zero or more repetitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated(0.., "abc", "|").parse_peek(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); +/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![]))); +/// # } +/// ``` +/// +/// One or more repetitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated(1.., "abc", "|").parse_peek(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); +/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag)))); +/// # } +/// ``` +/// +/// Fixed number of repetitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated(2, "abc", "|").parse_peek(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Err(ErrMode::Backtrack(InputError::new("123abc", ErrorKind::Tag)))); +/// assert_eq!(parser("abc|def"), Err(ErrMode::Backtrack(InputError::new("def", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag)))); +/// # } +/// ``` +/// +/// Arbitrary repetitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::separated; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// separated(0..=2, "abc", "|").parse_peek(s) +/// } +/// +/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"]))); +/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![]))); +/// # } +/// ``` +#[doc(alias = "sep_by")] +#[doc(alias = "sep_by1")] +#[doc(alias = "separated_list0")] +#[doc(alias = "separated_list1")] +#[doc(alias = "separated_m_n")] +#[inline(always)] +pub fn separated<I, O, C, O2, E, P, S>( + range: impl Into<Range>, + mut parser: P, + mut separator: S, +) -> impl Parser<I, C, E> +where + I: Stream, + C: Accumulate<O>, + P: Parser<I, O, E>, + S: Parser<I, O2, E>, + E: ParserError<I>, +{ + let Range { + start_inclusive, + end_inclusive, + } = range.into(); + trace("separated", move |input: &mut I| { + match (start_inclusive, end_inclusive) { + (0, None) => separated0_(&mut parser, &mut separator, input), + (1, None) => separated1_(&mut parser, &mut separator, input), + (start, end) if Some(start) == end => { + separated_n_(start, &mut parser, &mut separator, input) + } + (start, end) => separated_m_n_( + start, + end.unwrap_or(usize::MAX), + &mut parser, + &mut separator, + input, + ), + } + }) +} + +/// [`Accumulate`] the output of a parser, interleaved with `sep` +/// +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Arguments @@ -300,6 +502,7 @@ where /// ``` #[doc(alias = "sep_by")] #[doc(alias = "separated_list0")] +#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")] pub fn separated0<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E> where I: Stream, @@ -309,56 +512,74 @@ where E: ParserError<I>, { trace("separated0", move |i: &mut I| { - let mut res = C::initial(None); + separated0_(&mut parser, &mut sep, i) + }) +} - let start = i.checkpoint(); - match parser.parse_next(i) { +fn separated0_<I, O, C, O2, E, P, S>( + parser: &mut P, + separator: &mut S, + input: &mut I, +) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + P: Parser<I, O, E>, + S: Parser<I, O2, E>, + E: ParserError<I>, +{ + let mut acc = C::initial(None); + + let start = input.checkpoint(); + match parser.parse_next(input) { + Err(ErrMode::Backtrack(_)) => { + input.reset(start); + return Ok(acc); + } + Err(e) => return Err(e), + Ok(o) => { + acc.accumulate(o); + } + } + + loop { + let start = input.checkpoint(); + let len = input.eof_offset(); + match separator.parse_next(input) { Err(ErrMode::Backtrack(_)) => { - i.reset(start); - return Ok(res); + input.reset(start); + return Ok(acc); } Err(e) => return Err(e), - Ok(o) => { - res.accumulate(o); - } - } - - loop { - let start = i.checkpoint(); - let len = i.eof_offset(); - match sep.parse_next(i) { - Err(ErrMode::Backtrack(_)) => { - i.reset(start); - return Ok(res); + Ok(_) => { + // infinite loop check + if input.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`separated` separator parser must always consume", + )); } - Err(e) => return Err(e), - Ok(_) => { - // infinite loop check: the parser must always consume - if i.eof_offset() == len { - return Err(ErrMode::assert(i, "sep parsers must always consume")); - } - match parser.parse_next(i) { - Err(ErrMode::Backtrack(_)) => { - i.reset(start); - return Ok(res); - } - Err(e) => return Err(e), - Ok(o) => { - res.accumulate(o); - } + match parser.parse_next(input) { + Err(ErrMode::Backtrack(_)) => { + input.reset(start); + return Ok(acc); + } + Err(e) => return Err(e), + Ok(o) => { + acc.accumulate(o); } } } } - }) + } } -/// [`Accumulate`] the output of a parser, interleaed with `sep` +/// [`Accumulate`] the output of a parser, interleaved with `sep` /// /// Fails if the element parser does not produce at least one element.$ /// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Arguments @@ -387,6 +608,7 @@ where /// ``` #[doc(alias = "sep_by1")] #[doc(alias = "separated_list1")] +#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")] pub fn separated1<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E> where I: Stream, @@ -396,50 +618,209 @@ where E: ParserError<I>, { trace("separated1", move |i: &mut I| { - let mut res = C::initial(None); + separated1_(&mut parser, &mut sep, i) + }) +} + +fn separated1_<I, O, C, O2, E, P, S>( + parser: &mut P, + separator: &mut S, + input: &mut I, +) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + P: Parser<I, O, E>, + S: Parser<I, O2, E>, + E: ParserError<I>, +{ + let mut acc = C::initial(None); + + // Parse the first element + match parser.parse_next(input) { + Err(e) => return Err(e), + Ok(o) => { + acc.accumulate(o); + } + } - // Parse the first element - match parser.parse_next(i) { + loop { + let start = input.checkpoint(); + let len = input.eof_offset(); + match separator.parse_next(input) { + Err(ErrMode::Backtrack(_)) => { + input.reset(start); + return Ok(acc); + } Err(e) => return Err(e), - Ok(o) => { - res.accumulate(o); + Ok(_) => { + // infinite loop check + if input.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`separated` separator parser must always consume", + )); + } + + match parser.parse_next(input) { + Err(ErrMode::Backtrack(_)) => { + input.reset(start); + return Ok(acc); + } + Err(e) => return Err(e), + Ok(o) => { + acc.accumulate(o); + } + } } } + } +} - loop { - let start = i.checkpoint(); - let len = i.eof_offset(); - match sep.parse_next(i) { - Err(ErrMode::Backtrack(_)) => { - i.reset(start); - return Ok(res); +fn separated_n_<I, O, C, O2, E, P, S>( + count: usize, + parser: &mut P, + separator: &mut S, + input: &mut I, +) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + P: Parser<I, O, E>, + S: Parser<I, O2, E>, + E: ParserError<I>, +{ + let mut acc = C::initial(Some(count)); + + if count == 0 { + return Ok(acc); + } + + match parser.parse_next(input) { + Err(e) => { + return Err(e.append(input, ErrorKind::Many)); + } + Ok(o) => { + acc.accumulate(o); + } + } + + for _ in 1..count { + let len = input.eof_offset(); + match separator.parse_next(input) { + Err(e) => { + return Err(e.append(input, ErrorKind::Many)); + } + Ok(_) => { + // infinite loop check + if input.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`separated` separator parser must always consume", + )); } - Err(e) => return Err(e), - Ok(_) => { - // infinite loop check: the parser must always consume - if i.eof_offset() == len { - return Err(ErrMode::assert(i, "sep parsers must always consume")); + + match parser.parse_next(input) { + Err(e) => { + return Err(e.append(input, ErrorKind::Many)); + } + Ok(o) => { + acc.accumulate(o); } + } + } + } + } - match parser.parse_next(i) { - Err(ErrMode::Backtrack(_)) => { - i.reset(start); - return Ok(res); - } - Err(e) => return Err(e), - Ok(o) => { - res.accumulate(o); + Ok(acc) +} + +fn separated_m_n_<I, O, C, O2, E, P, S>( + min: usize, + max: usize, + parser: &mut P, + separator: &mut S, + input: &mut I, +) -> PResult<C, E> +where + I: Stream, + C: Accumulate<O>, + P: Parser<I, O, E>, + S: Parser<I, O2, E>, + E: ParserError<I>, +{ + if min > max { + return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); + } + + let mut acc = C::initial(Some(min)); + + let start = input.checkpoint(); + match parser.parse_next(input) { + Err(ErrMode::Backtrack(e)) => { + if min == 0 { + input.reset(start); + return Ok(acc); + } else { + return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); + } + } + Err(e) => return Err(e), + Ok(o) => { + acc.accumulate(o); + } + } + + for index in 1..max { + let start = input.checkpoint(); + let len = input.eof_offset(); + match separator.parse_next(input) { + Err(ErrMode::Backtrack(e)) => { + if index < min { + return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); + } else { + input.reset(start); + return Ok(acc); + } + } + Err(e) => { + return Err(e); + } + Ok(_) => { + // infinite loop check + if input.eof_offset() == len { + return Err(ErrMode::assert( + input, + "`separated` separator parser must always consume", + )); + } + + match parser.parse_next(input) { + Err(ErrMode::Backtrack(e)) => { + if index < min { + return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); + } else { + input.reset(start); + return Ok(acc); } } + Err(e) => { + return Err(e); + } + Ok(o) => { + acc.accumulate(o); + } } } } - }) + } + + Ok(acc) } /// Alternates between two parsers, merging the results (left associative) /// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Example @@ -506,7 +887,7 @@ where /// Alternates between two parsers, merging the results (right associative) /// -/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Example @@ -556,73 +937,6 @@ where }) } -fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E> -where - I: Stream, - C: Accumulate<O>, - F: Parser<I, O, E>, - E: ParserError<I>, -{ - if min > max { - return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many))); - } - - let mut res = C::initial(Some(min)); - for count in 0..max { - let start = input.checkpoint(); - let len = input.eof_offset(); - match parse.parse_next(input) { - Ok(value) => { - // infinite loop check: the parser must always consume - if input.eof_offset() == len { - return Err(ErrMode::assert( - input, - "`repeat` parsers must always consume", - )); - } - - res.accumulate(value); - } - Err(ErrMode::Backtrack(e)) => { - if count < min { - return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many))); - } else { - input.reset(start); - return Ok(res); - } - } - Err(e) => { - return Err(e); - } - } - } - - Ok(res) -} - -fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E> -where - I: Stream, - C: Accumulate<O>, - F: Parser<I, O, E>, - E: ParserError<I>, -{ - let mut res = C::initial(Some(count)); - - for _ in 0..count { - match f.parse_next(i) { - Ok(o) => { - res.accumulate(o); - } - Err(e) => { - return Err(e.append(i, ErrorKind::Many)); - } - } - } - - Ok(res) -} - /// Repeats the embedded parser, filling the given slice with results. /// /// This parser fails if the input runs out before the given slice is full. @@ -675,7 +989,7 @@ where /// Repeats the embedded parser `m..=n` times, calling `g` to gather the results /// -/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see +/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see /// [`cut_err`][crate::combinator::cut_err]. /// /// # Arguments diff --git a/vendor/winnow/src/combinator/parser.rs b/vendor/winnow/src/combinator/parser.rs index fb11adc15..c95f1f6f3 100644 --- a/vendor/winnow/src/combinator/parser.rs +++ b/vendor/winnow/src/combinator/parser.rs @@ -7,7 +7,7 @@ use crate::trace::trace; use crate::trace::trace_result; use crate::*; -/// Implementation of [`Parser::by_ref`][Parser::by_ref] +/// Implementation of [`Parser::by_ref`] #[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))] pub struct ByRef<'p, P> { p: &'p mut P, diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs index 9d2b49d80..27fa53456 100644 --- a/vendor/winnow/src/combinator/tests.rs +++ b/vendor/winnow/src/combinator/tests.rs @@ -717,13 +717,13 @@ fn permutation_test() { #[cfg(feature = "alloc")] fn separated0_test() { fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated0("abcd", ",").parse_peek(i) + separated(0.., "abcd", ",").parse_peek(i) } fn multi_empty(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated0("", ",").parse_peek(i) + separated(0.., "", ",").parse_peek(i) } fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated0("abcd", "..").parse_peek(i) + separated(0.., "abcd", "..").parse_peek(i) } let a = &b"abcdef"[..]; @@ -773,7 +773,7 @@ fn separated0_test() { #[cfg_attr(debug_assertions, should_panic)] fn separated0_empty_sep_test() { fn empty_sep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated0("abc", "").parse_peek(i) + separated(0.., "abc", "").parse_peek(i) } let i = &b"abcabc"[..]; @@ -792,10 +792,10 @@ fn separated0_empty_sep_test() { #[cfg(feature = "alloc")] fn separated1_test() { fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated1("abcd", ",").parse_peek(i) + separated(1.., "abcd", ",").parse_peek(i) } fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { - separated1("abcd", "..").parse_peek(i) + separated(1.., "abcd", "..").parse_peek(i) } let a = &b"abcdef"[..]; @@ -840,6 +840,47 @@ fn separated1_test() { #[test] #[cfg(feature = "alloc")] +fn separated_test() { + fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { + separated(2..=4, "abcd", ",").parse_peek(i) + } + + let a = &b"abcd,ef"[..]; + let b = &b"abcd,abcd,efgh"[..]; + let c = &b"abcd,abcd,abcd,abcd,efgh"[..]; + let d = &b"abcd,abcd,abcd,abcd,abcd,efgh"[..]; + let e = &b"abcd,ab"[..]; + + assert_eq!( + multi(Partial::new(a)), + Err(ErrMode::Backtrack(error_position!( + &Partial::new(&b"ef"[..]), + ErrorKind::Tag + ))) + ); + let res1 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(b)), + Ok((Partial::new(&b",efgh"[..]), res1)) + ); + let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(c)), + Ok((Partial::new(&b",efgh"[..]), res2)) + ); + let res3 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]]; + assert_eq!( + multi(Partial::new(d)), + Ok((Partial::new(&b",abcd,efgh"[..]), res3)) + ); + assert_eq!( + multi(Partial::new(e)), + Err(ErrMode::Incomplete(Needed::new(2))) + ); +} + +#[test] +#[cfg(feature = "alloc")] fn repeat0_test() { fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> { repeat(0.., "abcd").parse_peek(i) diff --git a/vendor/winnow/src/error.rs b/vendor/winnow/src/error.rs index 449bebc55..fd7d94695 100644 --- a/vendor/winnow/src/error.rs +++ b/vendor/winnow/src/error.rs @@ -4,12 +4,12 @@ //! - Accumulate more [context][Parser::context] as the error goes up the parser chain //! - Distinguish between [recoverable errors, //! unrecoverable errors, and more data is needed][ErrMode] -//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`) +//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `repeat`, `alt`) //! - Can be modified according to the user's needs, because some languages need a lot more information //! - Help thread-through the [stream][crate::stream] //! //! To abstract these needs away from the user, generally `winnow` parsers use the [`PResult`] -//! alias, rather than [`Result`][std::result::Result]. [`Parser::parse`] is a top-level operation +//! alias, rather than [`Result`]. [`Parser::parse`] is a top-level operation //! that can help convert to a `Result` for integrating with your application's error reporting. //! //! Error types include: @@ -30,26 +30,29 @@ use crate::stream::Stream; #[allow(unused_imports)] // Here for intra-doc links use crate::Parser; -/// Holds the result of [`Parser`] +/// For use with [`Parser::parse_peek`] which allows the input stream to be threaded through a +/// parser. /// /// - `Ok((I, O))` is the remaining [input][crate::stream] and the parsed value /// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it /// /// By default, the error type (`E`) is [`InputError`] /// -/// [`Parser::parse`] is a top-level operation that can help convert to a `Result` for integrating -/// with your application's error reporting. +/// When integrating into the result of the application, see +/// - [`Parser::parse`] +/// - [`ErrMode::into_inner`] pub type IResult<I, O, E = InputError<I>> = PResult<(I, O), E>; -/// Holds the result of [`Parser`] +/// For use with [`Parser::parse_next`] /// /// - `Ok(O)` is the parsed value /// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it /// -/// By default, the error type (`E`) is [`ErrorKind`]. +/// By default, the error type (`E`) is [`ContextError`]. /// -/// [`Parser::parse`] is a top-level operation that can help convert to a `Result` for integrating -/// with your application's error reporting. +/// When integrating into the result of the application, see +/// - [`Parser::parse`] +/// - [`ErrMode::into_inner`] pub type PResult<O, E = ContextError> = Result<O, ErrMode<E>>; /// Contains information on needed data if a parser returned `Incomplete` @@ -97,7 +100,7 @@ pub enum ErrMode<E> { /// /// More data needs to be buffered before retrying the parse. /// - /// This must only be set when the [`Stream`][crate::stream::Stream] is [partial][`crate::stream::StreamIsPartial`], like with + /// This must only be set when the [`Stream`] is [partial][`crate::stream::StreamIsPartial`], like with /// [`Partial`][crate::Partial] /// /// Convert this into an `Backtrack` with [`Parser::complete_err`] @@ -106,7 +109,7 @@ pub enum ErrMode<E> { /// /// For example, a parser for json values might include a /// [`dec_uint`][crate::ascii::dec_uint] as one case in an [`alt`][crate::combinator::alt] - /// combiantor. If it fails, the next case should be tried. + /// combinator. If it fails, the next case should be tried. Backtrack(E), /// The parser had an unrecoverable error. /// @@ -877,7 +880,7 @@ where #[cfg(feature = "std")] impl<I, C> TreeError<I, C> where - I: Clone + std::fmt::Display, + I: Clone + crate::lib::std::fmt::Display, C: fmt::Display, { fn write(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { @@ -1179,6 +1182,9 @@ impl<I, E> ParseError<I, E> { } /// The location in [`ParseError::input`] where parsing failed + /// + /// **Note:** This is an offset, not an index, and may point to the end of input + /// (`input.len()`) on eof errors. #[inline] pub fn offset(&self) -> usize { self.offset @@ -1219,21 +1225,21 @@ where writeln!(f, "parse error at line {}, column {}", line_num, col_num)?; // | - for _ in 0..=gutter { + for _ in 0..gutter { write!(f, " ")?; } - writeln!(f, "|")?; + writeln!(f, " |")?; // 1 | 00:32:00.a999999 write!(f, "{} | ", line_num)?; writeln!(f, "{}", String::from_utf8_lossy(content))?; // | ^ - for _ in 0..=gutter { + for _ in 0..gutter { write!(f, " ")?; } - write!(f, "|")?; - for _ in 0..=col_idx { + write!(f, " | ")?; + for _ in 0..col_idx { write!(f, " ")?; } // The span will be empty at eof, so we need to make sure we always print at least @@ -1246,7 +1252,7 @@ where } else { let content = input; writeln!(f, "{}", String::from_utf8_lossy(content))?; - for _ in 0..=span_start { + for _ in 0..span_start { write!(f, " ")?; } // The span will be empty at eof, so we need to make sure we always print at least @@ -1284,10 +1290,9 @@ fn translate_position(input: &[u8], index: usize) -> (usize, usize) { None => 0, }; let line = input[0..line_start].iter().filter(|b| **b == b'\n').count(); - let line = line; // HACK: This treats byte offset and column offsets the same - let column = std::str::from_utf8(&input[line_start..=index]) + let column = crate::lib::std::str::from_utf8(&input[line_start..=index]) .map(|s| s.chars().count() - 1) .unwrap_or_else(|_| index - line_start); let column = column + column_offset; @@ -1297,6 +1302,27 @@ fn translate_position(input: &[u8], index: usize) -> (usize, usize) { #[cfg(test)] #[cfg(feature = "std")] +mod test_parse_error { + use super::*; + + #[test] + fn single_line() { + let mut input = "0xZ123"; + let start = input.checkpoint(); + let _ = input.next_token().unwrap(); + let _ = input.next_token().unwrap(); + let inner = InputError::new(input, ErrorKind::Slice); + let error = ParseError::new(input, start, inner); + let expected = "\ +0xZ123 + ^ +slice error starting at: Z123"; + assert_eq!(error.to_string(), expected); + } +} + +#[cfg(test)] +#[cfg(feature = "std")] mod test_translate_position { use super::*; diff --git a/vendor/winnow/src/lib.rs b/vendor/winnow/src/lib.rs index 5614b7f11..4a21b9e11 100644 --- a/vendor/winnow/src/lib.rs +++ b/vendor/winnow/src/lib.rs @@ -49,6 +49,7 @@ #![cfg_attr(docsrs, feature(extended_key_value_attributes))] #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +#![warn(clippy::std_instead_of_core)] // BEGIN - Embark standard lints v6 for Rust 1.55+ // do not change or add/remove here, but one can add exceptions after this section // for more info see: <https://github.com/EmbarkStudios/rust-ecosystem/issues/59> @@ -175,6 +176,7 @@ pub(crate) mod lib { #[cfg(feature = "std")] /// internal std exports for `no_std` compatibility pub mod std { + #![allow(clippy::std_instead_of_core)] #[doc(hidden)] pub use std::{ alloc, borrow, boxed, cmp, collections, convert, fmt, hash, iter, mem, ops, option, diff --git a/vendor/winnow/src/parser.rs b/vendor/winnow/src/parser.rs index b59e4cd83..8a1040dc9 100644 --- a/vendor/winnow/src/parser.rs +++ b/vendor/winnow/src/parser.rs @@ -1,5 +1,6 @@ //! Basic types to build the parsers +use crate::ascii::Caseless as AsciiCaseless; use crate::combinator::*; use crate::error::{AddContext, FromExternalError, IResult, PResult, ParseError, ParserError}; use crate::stream::{AsChar, Compare, Location, ParseSlice, Stream, StreamIsPartial}; @@ -91,7 +92,7 @@ pub trait Parser<I, O, E> { /// /// # Example /// - /// Because parsers are `FnMut`, they can be called multiple times. This prevents moving `f` + /// Because parsers are `FnMut`, they can be called multiple times. This prevents moving `f` /// into [`length_data`][crate::binary::length_data] and `g` into /// [`Parser::complete_err`]: /// ```rust,compile_fail @@ -194,11 +195,11 @@ pub trait Parser<I, O, E> { /// use winnow::ascii::alpha1; /// # fn main() { /// - /// fn parser1<'s>(i: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> { - /// alpha1(i) - /// } + /// fn parser1<'s>(i: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> { + /// alpha1(i) + /// } /// - /// let mut parser2 = parser1.output_into(); + /// let mut parser2 = parser1.output_into(); /// /// // the parser converts the &str output of the child parser into a Vec<u8> /// let bytes: IResult<&str, Vec<u8>> = parser2.parse_peek("abcd"); @@ -742,6 +743,38 @@ where /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; /// # use winnow::combinator::alt; /// # use winnow::token::take; +/// use winnow::ascii::Caseless; +/// +/// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> { +/// alt((Caseless(&"hello"[..]), take(5usize))).parse_next(s) +/// } +/// +/// assert_eq!(parser.parse_peek(&b"Hello, World!"[..]), Ok((&b", World!"[..], &b"Hello"[..]))); +/// assert_eq!(parser.parse_peek(&b"hello, World!"[..]), Ok((&b", World!"[..], &b"hello"[..]))); +/// assert_eq!(parser.parse_peek(&b"HeLlo, World!"[..]), Ok((&b", World!"[..], &b"HeLlo"[..]))); +/// assert_eq!(parser.parse_peek(&b"Something"[..]), Ok((&b"hing"[..], &b"Somet"[..]))); +/// assert_eq!(parser.parse_peek(&b"Some"[..]), Err(ErrMode::Backtrack(InputError::new(&b"Some"[..], ErrorKind::Slice)))); +/// assert_eq!(parser.parse_peek(&b""[..]), Err(ErrMode::Backtrack(InputError::new(&b""[..], ErrorKind::Slice)))); +/// ``` +impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for AsciiCaseless<&'s [u8]> +where + I: Compare<AsciiCaseless<&'s [u8]>> + StreamIsPartial, + I: Stream, +{ + #[inline(always)] + fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> { + crate::token::tag(*self).parse_next(i) + } +} + +/// This is a shortcut for [`tag`][crate::token::tag]. +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; /// /// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> { /// alt((b"Hello", take(5usize))).parse_next(s) @@ -768,6 +801,39 @@ where /// # Example /// ```rust /// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; +/// use winnow::ascii::Caseless; +/// +/// fn parser<'s>(s: &mut &'s [u8]) -> PResult<&'s [u8], InputError<&'s [u8]>> { +/// alt((Caseless(b"hello"), take(5usize))).parse_next(s) +/// } +/// +/// assert_eq!(parser.parse_peek(&b"Hello, World!"[..]), Ok((&b", World!"[..], &b"Hello"[..]))); +/// assert_eq!(parser.parse_peek(&b"hello, World!"[..]), Ok((&b", World!"[..], &b"hello"[..]))); +/// assert_eq!(parser.parse_peek(&b"HeLlo, World!"[..]), Ok((&b", World!"[..], &b"HeLlo"[..]))); +/// assert_eq!(parser.parse_peek(&b"Something"[..]), Ok((&b"hing"[..], &b"Somet"[..]))); +/// assert_eq!(parser.parse_peek(&b"Some"[..]), Err(ErrMode::Backtrack(InputError::new(&b"Some"[..], ErrorKind::Slice)))); +/// assert_eq!(parser.parse_peek(&b""[..]), Err(ErrMode::Backtrack(InputError::new(&b""[..], ErrorKind::Slice)))); +/// ``` +impl<'s, I, E: ParserError<I>, const N: usize> Parser<I, <I as Stream>::Slice, E> + for AsciiCaseless<&'s [u8; N]> +where + I: Compare<AsciiCaseless<&'s [u8; N]>> + StreamIsPartial, + I: Stream, +{ + #[inline(always)] + fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> { + crate::token::tag(*self).parse_next(i) + } +} + +/// This is a shortcut for [`tag`][crate::token::tag]. +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; /// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}}; /// # use winnow::combinator::alt; /// # use winnow::token::take; @@ -792,6 +858,38 @@ where } } +/// This is a shortcut for [`tag`][crate::token::tag]. +/// +/// # Example +/// ```rust +/// # use winnow::prelude::*; +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}}; +/// # use winnow::combinator::alt; +/// # use winnow::token::take; +/// # use winnow::ascii::Caseless; +/// +/// fn parser<'s>(s: &mut &'s str) -> PResult<&'s str, InputError<&'s str>> { +/// alt((Caseless("hello"), take(5usize))).parse_next(s) +/// } +/// +/// assert_eq!(parser.parse_peek("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser.parse_peek("hello, World!"), Ok((", World!", "hello"))); +/// assert_eq!(parser.parse_peek("HeLlo, World!"), Ok((", World!", "HeLlo"))); +/// assert_eq!(parser.parse_peek("Something"), Ok(("hing", "Somet"))); +/// assert_eq!(parser.parse_peek("Some"), Err(ErrMode::Backtrack(InputError::new("Some", ErrorKind::Slice)))); +/// assert_eq!(parser.parse_peek(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice)))); +/// ``` +impl<'s, I, E: ParserError<I>> Parser<I, <I as Stream>::Slice, E> for AsciiCaseless<&'s str> +where + I: Compare<AsciiCaseless<&'s str>> + StreamIsPartial, + I: Stream, +{ + #[inline(always)] + fn parse_next(&mut self, i: &mut I) -> PResult<<I as Stream>::Slice, E> { + crate::token::tag(*self).parse_next(i) + } +} + impl<I, E: ParserError<I>> Parser<I, (), E> for () { #[inline(always)] fn parse_next(&mut self, _i: &mut I) -> PResult<(), E> { diff --git a/vendor/winnow/src/stream/impls.rs b/vendor/winnow/src/stream/impls.rs index b277dd9a9..d76e1bf35 100644 --- a/vendor/winnow/src/stream/impls.rs +++ b/vendor/winnow/src/stream/impls.rs @@ -238,14 +238,14 @@ mod bytes { impl PartialOrd for Bytes { #[inline] fn partial_cmp(&self, other: &Bytes) -> Option<Ordering> { - PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes()) + Some(self.cmp(other)) } } impl Ord for Bytes { #[inline] fn cmp(&self, other: &Bytes) -> Ordering { - self.partial_cmp(other).unwrap() + Ord::cmp(self.as_bytes(), other.as_bytes()) } } @@ -485,14 +485,14 @@ mod bstr { impl PartialOrd for BStr { #[inline] fn partial_cmp(&self, other: &BStr) -> Option<Ordering> { - PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes()) + Some(self.cmp(other)) } } impl Ord for BStr { #[inline] fn cmp(&self, other: &BStr) -> Ordering { - self.partial_cmp(other).unwrap() + Ord::cmp(self.as_bytes(), other.as_bytes()) } } diff --git a/vendor/winnow/src/stream/mod.rs b/vendor/winnow/src/stream/mod.rs index 5f2152e27..d0af80f3e 100644 --- a/vendor/winnow/src/stream/mod.rs +++ b/vendor/winnow/src/stream/mod.rs @@ -9,8 +9,10 @@ //! - [`Partial`] can mark an input as partial buffer that is being streamed into //! - [Custom stream types][crate::_topic::stream] +use core::hash::BuildHasher; use core::num::NonZeroUsize; +use crate::ascii::Caseless as AsciiCaseless; use crate::error::Needed; use crate::lib::std::iter::{Cloned, Enumerate}; use crate::lib::std::slice::Iter; @@ -24,8 +26,12 @@ use crate::error::ErrMode; #[cfg(feature = "alloc")] use crate::lib::std::collections::BTreeMap; +#[cfg(feature = "alloc")] +use crate::lib::std::collections::BTreeSet; #[cfg(feature = "std")] use crate::lib::std::collections::HashMap; +#[cfg(feature = "std")] +use crate::lib::std::collections::HashSet; #[cfg(feature = "alloc")] use crate::lib::std::string::String; #[cfg(feature = "alloc")] @@ -88,6 +94,15 @@ impl BStr { /// Allow collecting the span of a parsed token /// +/// Spans are tracked as a [`Range<usize>`] of byte offsets. +/// +/// Converting byte offsets to line or column numbers is left up to the user, as computing column +/// numbers requires domain knowledge (are columns byte-based, codepoint-based, or grapheme-based?) +/// and O(n) iteration over the input to determine codepoint and line boundaries. +/// +/// [The `line-span` crate](https://docs.rs/line-span/latest/line_span/) can help with converting +/// byte offsets to line numbers. +/// /// See [`Parser::span`][crate::Parser::span] and [`Parser::with_span`][crate::Parser::with_span] for more details #[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Located<I> { @@ -202,7 +217,7 @@ impl<I: crate::lib::std::fmt::Display, S> crate::lib::std::fmt::Display for Stat /// Mark the input as a partial buffer for streaming input. /// -/// Complete input means that we already have all of the data. This will be the common case with +/// Complete input means that we already have all of the data. This will be the common case with /// small files that can be read entirely to memory. /// /// In contrast, streaming input assumes that we might not have all of the data. @@ -322,6 +337,13 @@ pub trait SliceLen { fn slice_len(&self) -> usize; } +impl<S: SliceLen> SliceLen for AsciiCaseless<S> { + #[inline(always)] + fn slice_len(&self) -> usize { + self.0.slice_len() + } +} + impl<'a, T> SliceLen for &'a [T] { #[inline] fn slice_len(&self) -> usize { @@ -423,7 +445,8 @@ pub trait Stream: Offset<<Self as Stream>::Checkpoint> + crate::lib::std::fmt::D /// Iterate with the offset from the current location fn iter_offsets(&self) -> Self::IterOffsets; - /// Returns the offaet to the end of the input + + /// Returns the offset to the end of the input fn eof_offset(&self) -> usize; /// Split off the next token from the input @@ -450,7 +473,7 @@ pub trait Stream: Offset<<Self as Stream>::Checkpoint> + crate::lib::std::fmt::D /// Split off a slice of tokens from the input /// /// **NOTE:** For inputs with variable width tokens, like `&str`'s `char`, `offset` might not correspond - /// with the number of tokens. To get a valid offset, use: + /// with the number of tokens. To get a valid offset, use: /// - [`Stream::eof_offset`] /// - [`Stream::iter_offsets`] /// - [`Stream::offset_for`] @@ -1276,7 +1299,10 @@ where /// Useful functions to calculate the offset between slices and show a hexdump of a slice pub trait Offset<Start = Self> { - /// Offset between the first byte of `start` and the first byte of `self` + /// Offset between the first byte of `start` and the first byte of `self`a + /// + /// **Note:** This is an offset, not an index, and may point to the end of input + /// (`start.len()`) when `self` is exhausted. fn offset_from(&self, start: &Start) -> usize; } @@ -1288,9 +1314,9 @@ impl<'a, T> Offset for &'a [T] { debug_assert!( fst <= snd, - "`Offset::offset_to` only accepts slices of `self`" + "`Offset::offset_from({snd:?}, {fst:?})` only accepts slices of `self`" ); - snd as usize - fst as usize + (snd as usize - fst as usize) / crate::lib::std::mem::size_of::<T>() } } @@ -1567,47 +1593,50 @@ pub trait Compare<T> { /// by lowercasing both strings and comparing /// the result. This is a temporary solution until /// a better one appears + #[deprecated(since = "0.5.20", note = "Replaced with `compare(ascii::Caseless(_))`")] fn compare_no_case(&self, t: T) -> CompareResult; } -fn lowercase_byte(c: u8) -> u8 { - match c { - b'A'..=b'Z' => c - b'A' + b'a', - _ => c, - } -} - impl<'a, 'b> Compare<&'b [u8]> for &'a [u8] { #[inline] fn compare(&self, t: &'b [u8]) -> CompareResult { - let pos = self.iter().zip(t.iter()).position(|(a, b)| a != b); - - match pos { - Some(_) => CompareResult::Error, - None => { - if self.len() >= t.len() { - CompareResult::Ok - } else { - CompareResult::Incomplete - } - } + if t.iter().zip(*self).any(|(a, b)| a != b) { + CompareResult::Error + } else if self.len() < t.slice_len() { + CompareResult::Incomplete + } else { + CompareResult::Ok } } - #[inline] + #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { - if self + self.compare(AsciiCaseless(t)) + } +} + +impl<'a, 'b> Compare<AsciiCaseless<&'b [u8]>> for &'a [u8] { + #[inline] + fn compare(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult { + if t.0 .iter() - .zip(t) - .any(|(a, b)| lowercase_byte(*a) != lowercase_byte(*b)) + .zip(*self) + .any(|(a, b)| !a.eq_ignore_ascii_case(b)) { CompareResult::Error - } else if self.len() < t.len() { + } else if self.len() < t.slice_len() { CompareResult::Incomplete } else { CompareResult::Ok } } + + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult { + self.compare(t) + } } impl<'a, const LEN: usize> Compare<[u8; LEN]> for &'a [u8] { @@ -1617,11 +1646,25 @@ impl<'a, const LEN: usize> Compare<[u8; LEN]> for &'a [u8] { } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: [u8; LEN]) -> CompareResult { self.compare_no_case(&t[..]) } } +impl<'a, const LEN: usize> Compare<AsciiCaseless<[u8; LEN]>> for &'a [u8] { + #[inline(always)] + fn compare(&self, t: AsciiCaseless<[u8; LEN]>) -> CompareResult { + self.compare(AsciiCaseless(&t.0[..])) + } + + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<[u8; LEN]>) -> CompareResult { + self.compare_no_case(AsciiCaseless(&t.0[..])) + } +} + impl<'a, 'b, const LEN: usize> Compare<&'b [u8; LEN]> for &'a [u8] { #[inline(always)] fn compare(&self, t: &'b [u8; LEN]) -> CompareResult { @@ -1629,46 +1672,72 @@ impl<'a, 'b, const LEN: usize> Compare<&'b [u8; LEN]> for &'a [u8] { } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: &'b [u8; LEN]) -> CompareResult { self.compare_no_case(&t[..]) } } +impl<'a, 'b, const LEN: usize> Compare<AsciiCaseless<&'b [u8; LEN]>> for &'a [u8] { + #[inline(always)] + fn compare(&self, t: AsciiCaseless<&'b [u8; LEN]>) -> CompareResult { + self.compare(AsciiCaseless(&t.0[..])) + } + + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<&'b [u8; LEN]>) -> CompareResult { + self.compare_no_case(AsciiCaseless(&t.0[..])) + } +} + impl<'a, 'b> Compare<&'b str> for &'a [u8] { #[inline(always)] fn compare(&self, t: &'b str) -> CompareResult { self.compare(t.as_bytes()) } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: &'b str) -> CompareResult { self.compare_no_case(t.as_bytes()) } } +impl<'a, 'b> Compare<AsciiCaseless<&'b str>> for &'a [u8] { + #[inline(always)] + fn compare(&self, t: AsciiCaseless<&'b str>) -> CompareResult { + self.compare(AsciiCaseless(t.0.as_bytes())) + } + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<&'b str>) -> CompareResult { + self.compare_no_case(AsciiCaseless(t.0.as_bytes())) + } +} + impl<'a, 'b> Compare<&'b str> for &'a str { #[inline(always)] fn compare(&self, t: &'b str) -> CompareResult { self.as_bytes().compare(t.as_bytes()) } - //FIXME: this version is too simple and does not use the current locale #[inline] + #[allow(deprecated)] fn compare_no_case(&self, t: &'b str) -> CompareResult { - let pos = self - .chars() - .zip(t.chars()) - .position(|(a, b)| a.to_lowercase().ne(b.to_lowercase())); + self.compare(AsciiCaseless(t)) + } +} - match pos { - Some(_) => CompareResult::Error, - None => { - if self.len() >= t.len() { - CompareResult::Ok - } else { - CompareResult::Incomplete - } - } - } +impl<'a, 'b> Compare<AsciiCaseless<&'b str>> for &'a str { + #[inline(always)] + fn compare(&self, t: AsciiCaseless<&'b str>) -> CompareResult { + self.as_bytes().compare(t.as_bytes()) + } + + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<&'b str>) -> CompareResult { + self.compare(t) } } @@ -1678,11 +1747,24 @@ impl<'a, 'b> Compare<&'b [u8]> for &'a str { AsBStr::as_bstr(self).compare(t) } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: &'b [u8]) -> CompareResult { AsBStr::as_bstr(self).compare_no_case(t) } } +impl<'a, 'b> Compare<AsciiCaseless<&'b [u8]>> for &'a str { + #[inline(always)] + fn compare(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult { + AsBStr::as_bstr(self).compare(t) + } + #[inline(always)] + #[allow(deprecated)] + fn compare_no_case(&self, t: AsciiCaseless<&'b [u8]>) -> CompareResult { + AsBStr::as_bstr(self).compare_no_case(t) + } +} + impl<'a, T> Compare<T> for &'a Bytes where &'a [u8]: Compare<T>, @@ -1694,6 +1776,7 @@ where } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: T) -> CompareResult { let bytes = (*self).as_bytes(); bytes.compare_no_case(t) @@ -1711,6 +1794,7 @@ where } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: T) -> CompareResult { let bytes = (*self).as_bytes(); bytes.compare_no_case(t) @@ -1727,6 +1811,7 @@ where } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, other: U) -> CompareResult { self.input.compare_no_case(other) } @@ -1742,6 +1827,7 @@ where } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, other: U) -> CompareResult { self.input.compare_no_case(other) } @@ -1757,6 +1843,7 @@ where } #[inline(always)] + #[allow(deprecated)] fn compare_no_case(&self, t: T) -> CompareResult { self.input.compare_no_case(t) } @@ -1775,6 +1862,27 @@ impl<'i, 's> FindSlice<&'s [u8]> for &'i [u8] { } } +impl<'i, 's> FindSlice<(&'s [u8],)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s [u8],)) -> Option<usize> { + memmem(self, substr.0) + } +} + +impl<'i, 's> FindSlice<(&'s [u8], &'s [u8])> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s [u8], &'s [u8])) -> Option<usize> { + memmem2(self, substr) + } +} + +impl<'i, 's> FindSlice<(&'s [u8], &'s [u8], &'s [u8])> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s [u8], &'s [u8], &'s [u8])) -> Option<usize> { + memmem3(self, substr) + } +} + impl<'i> FindSlice<u8> for &'i [u8] { #[inline(always)] fn find_slice(&self, substr: u8) -> Option<usize> { @@ -1782,6 +1890,27 @@ impl<'i> FindSlice<u8> for &'i [u8] { } } +impl<'i> FindSlice<(u8,)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (u8,)) -> Option<usize> { + memchr(substr.0, self) + } +} + +impl<'i> FindSlice<(u8, u8)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (u8, u8)) -> Option<usize> { + memchr2(substr, self) + } +} + +impl<'i> FindSlice<(u8, u8, u8)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (u8, u8, u8)) -> Option<usize> { + memchr3(substr, self) + } +} + impl<'i, 's> FindSlice<&'s str> for &'i [u8] { #[inline(always)] fn find_slice(&self, substr: &'s str) -> Option<usize> { @@ -1789,17 +1918,129 @@ impl<'i, 's> FindSlice<&'s str> for &'i [u8] { } } +impl<'i, 's> FindSlice<(&'s str,)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s str,)) -> Option<usize> { + memmem(self, substr.0.as_bytes()) + } +} + +impl<'i, 's> FindSlice<(&'s str, &'s str)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s str, &'s str)) -> Option<usize> { + memmem2(self, (substr.0.as_bytes(), substr.1.as_bytes())) + } +} + +impl<'i, 's> FindSlice<(&'s str, &'s str, &'s str)> for &'i [u8] { + #[inline(always)] + fn find_slice(&self, substr: (&'s str, &'s str, &'s str)) -> Option<usize> { + memmem3( + self, + ( + substr.0.as_bytes(), + substr.1.as_bytes(), + substr.2.as_bytes(), + ), + ) + } +} + impl<'i, 's> FindSlice<&'s str> for &'i str { #[inline(always)] fn find_slice(&self, substr: &'s str) -> Option<usize> { - self.find(substr) + self.as_bytes().find_slice(substr.as_bytes()) + } +} + +impl<'i, 's> FindSlice<(&'s str,)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (&'s str,)) -> Option<usize> { + self.as_bytes().find_slice(substr) + } +} + +impl<'i, 's> FindSlice<(&'s str, &'s str)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (&'s str, &'s str)) -> Option<usize> { + self.as_bytes().find_slice(substr) + } +} + +impl<'i, 's> FindSlice<(&'s str, &'s str, &'s str)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (&'s str, &'s str, &'s str)) -> Option<usize> { + self.as_bytes().find_slice(substr) } } impl<'i> FindSlice<char> for &'i str { #[inline(always)] fn find_slice(&self, substr: char) -> Option<usize> { - self.find(substr) + let mut b = [0; 4]; + let substr = substr.encode_utf8(&mut b); + self.find_slice(&*substr) + } +} + +impl<'i> FindSlice<(char,)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (char,)) -> Option<usize> { + let mut b = [0; 4]; + let substr0 = substr.0.encode_utf8(&mut b); + self.find_slice((&*substr0,)) + } +} + +impl<'i> FindSlice<(char, char)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (char, char)) -> Option<usize> { + let mut b = [0; 4]; + let substr0 = substr.0.encode_utf8(&mut b); + let mut b = [0; 4]; + let substr1 = substr.1.encode_utf8(&mut b); + self.find_slice((&*substr0, &*substr1)) + } +} + +impl<'i> FindSlice<(char, char, char)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (char, char, char)) -> Option<usize> { + let mut b = [0; 4]; + let substr0 = substr.0.encode_utf8(&mut b); + let mut b = [0; 4]; + let substr1 = substr.1.encode_utf8(&mut b); + let mut b = [0; 4]; + let substr2 = substr.2.encode_utf8(&mut b); + self.find_slice((&*substr0, &*substr1, &*substr2)) + } +} + +impl<'i> FindSlice<u8> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: u8) -> Option<usize> { + self.find_slice(substr.as_char()) + } +} + +impl<'i> FindSlice<(u8,)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (u8,)) -> Option<usize> { + self.find_slice((substr.0.as_char(),)) + } +} + +impl<'i> FindSlice<(u8, u8)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (u8, u8)) -> Option<usize> { + self.find_slice((substr.0.as_char(), substr.1.as_char())) + } +} + +impl<'i> FindSlice<(u8, u8, u8)> for &'i str { + #[inline(always)] + fn find_slice(&self, substr: (u8, u8, u8)) -> Option<usize> { + self.find_slice((substr.0.as_char(), substr.1.as_char(), substr.2.as_char())) } } @@ -1953,7 +2194,7 @@ where } } -/// Ensure checkpoint details are kept privazte +/// Ensure checkpoint details are kept private #[derive(Copy, Clone, Debug)] pub struct Checkpoint<T>(T); @@ -2177,15 +2418,19 @@ where } #[cfg(feature = "std")] -impl<K, V> Accumulate<(K, V)> for HashMap<K, V> +impl<K, V, S> Accumulate<(K, V)> for HashMap<K, V, S> where K: crate::lib::std::cmp::Eq + crate::lib::std::hash::Hash, + S: BuildHasher + Default, { #[inline(always)] fn initial(capacity: Option<usize>) -> Self { + let h = S::default(); match capacity { - Some(capacity) => HashMap::with_capacity(clamp_capacity::<(K, V)>(capacity)), - None => HashMap::new(), + Some(capacity) => { + HashMap::with_capacity_and_hasher(clamp_capacity::<(K, V)>(capacity), h) + } + None => HashMap::with_hasher(h), } } #[inline(always)] @@ -2195,6 +2440,41 @@ where } #[cfg(feature = "alloc")] +impl<K> Accumulate<K> for BTreeSet<K> +where + K: crate::lib::std::cmp::Ord, +{ + #[inline(always)] + fn initial(_capacity: Option<usize>) -> Self { + BTreeSet::new() + } + #[inline(always)] + fn accumulate(&mut self, key: K) { + self.insert(key); + } +} + +#[cfg(feature = "std")] +impl<K, S> Accumulate<K> for HashSet<K, S> +where + K: crate::lib::std::cmp::Eq + crate::lib::std::hash::Hash, + S: BuildHasher + Default, +{ + #[inline(always)] + fn initial(capacity: Option<usize>) -> Self { + let h = S::default(); + match capacity { + Some(capacity) => HashSet::with_capacity_and_hasher(clamp_capacity::<K>(capacity), h), + None => HashSet::with_hasher(h), + } + } + #[inline(always)] + fn accumulate(&mut self, key: K) { + self.insert(key); + } +} + +#[cfg(feature = "alloc")] #[inline] pub(crate) fn clamp_capacity<T>(capacity: usize) -> usize { /// Don't pre-allocate more than 64KiB when calling `Vec::with_capacity`. @@ -2520,7 +2800,7 @@ impl<C: AsChar> ContainsToken<C> for char { } } -impl<C: AsChar, F: Fn(C) -> bool> ContainsToken<C> for F { +impl<C, F: Fn(C) -> bool> ContainsToken<C> for F { #[inline(always)] fn contains_token(&self, token: C) -> bool { self(token) @@ -2675,51 +2955,158 @@ fn memchr(token: u8, slice: &[u8]) -> Option<usize> { memchr::memchr(token, slice) } +#[cfg(feature = "simd")] +#[inline(always)] +fn memchr2(token: (u8, u8), slice: &[u8]) -> Option<usize> { + memchr::memchr2(token.0, token.1, slice) +} + +#[cfg(feature = "simd")] +#[inline(always)] +fn memchr3(token: (u8, u8, u8), slice: &[u8]) -> Option<usize> { + memchr::memchr3(token.0, token.1, token.2, slice) +} + #[cfg(not(feature = "simd"))] #[inline(always)] fn memchr(token: u8, slice: &[u8]) -> Option<usize> { slice.iter().position(|t| *t == token) } -#[cfg(feature = "simd")] +#[cfg(not(feature = "simd"))] +#[inline(always)] +fn memchr2(token: (u8, u8), slice: &[u8]) -> Option<usize> { + slice.iter().position(|t| *t == token.0 || *t == token.1) +} + +#[cfg(not(feature = "simd"))] +#[inline(always)] +fn memchr3(token: (u8, u8, u8), slice: &[u8]) -> Option<usize> { + slice + .iter() + .position(|t| *t == token.0 || *t == token.1 || *t == token.2) +} + #[inline(always)] fn memmem(slice: &[u8], tag: &[u8]) -> Option<usize> { - if tag.len() > slice.len() { - return None; + if tag.len() == 1 { + memchr(tag[0], slice) + } else { + memmem_(slice, tag) + } +} + +#[inline(always)] +fn memmem2(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> { + if tag.0.len() == 1 && tag.1.len() == 1 { + memchr2((tag.0[0], tag.1[0]), slice) + } else { + memmem2_(slice, tag) + } +} + +#[inline(always)] +fn memmem3(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> { + if tag.0.len() == 1 && tag.1.len() == 1 && tag.2.len() == 1 { + memchr3((tag.0[0], tag.1[0], tag.2[0]), slice) + } else { + memmem3_(slice, tag) } +} - let (&substr_first, substr_rest) = match tag.split_first() { - Some(split) => split, - // an empty substring is found at position 0 - // This matches the behavior of str.find(""). +#[cfg(feature = "simd")] +#[inline(always)] +fn memmem_(slice: &[u8], tag: &[u8]) -> Option<usize> { + let &prefix = match tag.first() { + Some(x) => x, None => return Some(0), }; - - if substr_rest.is_empty() { - return memchr::memchr(substr_first, slice); + #[allow(clippy::manual_find)] // faster this way + for i in memchr::memchr_iter(prefix, slice) { + if slice[i..].starts_with(tag) { + return Some(i); + } } + None +} - let mut offset = 0; - let haystack = &slice[..slice.len() - substr_rest.len()]; +#[cfg(feature = "simd")] +fn memmem2_(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> { + let prefix = match (tag.0.first(), tag.1.first()) { + (Some(&a), Some(&b)) => (a, b), + _ => return Some(0), + }; + #[allow(clippy::manual_find)] // faster this way + for i in memchr::memchr2_iter(prefix.0, prefix.1, slice) { + let subslice = &slice[i..]; + if subslice.starts_with(tag.0) { + return Some(i); + } + if subslice.starts_with(tag.1) { + return Some(i); + } + } + None +} - while let Some(position) = memchr::memchr(substr_first, &haystack[offset..]) { - offset += position; - let next_offset = offset + 1; - if &slice[next_offset..][..substr_rest.len()] == substr_rest { - return Some(offset); +#[cfg(feature = "simd")] +fn memmem3_(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> { + let prefix = match (tag.0.first(), tag.1.first(), tag.2.first()) { + (Some(&a), Some(&b), Some(&c)) => (a, b, c), + _ => return Some(0), + }; + #[allow(clippy::manual_find)] // faster this way + for i in memchr::memchr3_iter(prefix.0, prefix.1, prefix.2, slice) { + let subslice = &slice[i..]; + if subslice.starts_with(tag.0) { + return Some(i); + } + if subslice.starts_with(tag.1) { + return Some(i); } + if subslice.starts_with(tag.2) { + return Some(i); + } + } + None +} - offset = next_offset; +#[cfg(not(feature = "simd"))] +fn memmem_(slice: &[u8], tag: &[u8]) -> Option<usize> { + for i in 0..slice.len() { + let subslice = &slice[i..]; + if subslice.starts_with(tag) { + return Some(i); + } } + None +} +#[cfg(not(feature = "simd"))] +fn memmem2_(slice: &[u8], tag: (&[u8], &[u8])) -> Option<usize> { + for i in 0..slice.len() { + let subslice = &slice[i..]; + if subslice.starts_with(tag.0) { + return Some(i); + } + if subslice.starts_with(tag.1) { + return Some(i); + } + } None } #[cfg(not(feature = "simd"))] -fn memmem(slice: &[u8], tag: &[u8]) -> Option<usize> { +fn memmem3_(slice: &[u8], tag: (&[u8], &[u8], &[u8])) -> Option<usize> { for i in 0..slice.len() { let subslice = &slice[i..]; - if subslice.starts_with(tag) { + if subslice.starts_with(tag.0) { + return Some(i); + } + if subslice.starts_with(tag.1) { + return Some(i); + } + if subslice.starts_with(tag.2) { return Some(i); } } diff --git a/vendor/winnow/src/stream/tests.rs b/vendor/winnow/src/stream/tests.rs index e653ad9e0..0129f6e3f 100644 --- a/vendor/winnow/src/stream/tests.rs +++ b/vendor/winnow/src/stream/tests.rs @@ -1,8 +1,25 @@ #[cfg(feature = "std")] use proptest::prelude::*; +use crate::{ + combinator::{separated, separated_pair}, + PResult, Parser, +}; + use super::*; +#[cfg(feature = "std")] +#[test] +fn test_fxhashmap_compiles() { + let input = "a=b"; + fn pair(i: &mut &str) -> PResult<(char, char)> { + let out = separated_pair('a', '=', 'b').parse_next(i)?; + Ok(out) + } + + let _: rustc_hash::FxHashMap<char, char> = separated(0.., pair, ',').parse(input).unwrap(); +} + #[test] fn test_offset_u8() { let s = b"abcd123"; @@ -114,3 +131,18 @@ fn test_partial_complete() { i.restore_partial(incomplete_state); assert!(i.is_partial(), "incomplete stream state should be restored"); } + +#[test] +fn test_custom_slice() { + type Token = usize; + type TokenSlice<'i> = &'i [Token]; + + let mut tokens: TokenSlice<'_> = &[1, 2, 3, 4]; + + let input = &mut tokens; + let start = input.checkpoint(); + let _ = input.next_token(); + let _ = input.next_token(); + let offset = input.offset_from(&start); + assert_eq!(offset, 2); +} diff --git a/vendor/winnow/src/token/mod.rs b/vendor/winnow/src/token/mod.rs index fba019c97..839821f79 100644 --- a/vendor/winnow/src/token/mod.rs +++ b/vendor/winnow/src/token/mod.rs @@ -81,7 +81,7 @@ where /// /// It will return `Err(ErrMode::Backtrack(InputError::new(_, ErrorKind::Tag)))` if the input doesn't match the pattern /// -/// **Note:** [`Parser`][crate::Parser] is implemented for strings and byte strings as a convenience (complete +/// **Note:** [`Parser`] is implemented for strings and byte strings as a convenience (complete /// only) /// /// # Example @@ -114,6 +114,23 @@ where /// assert_eq!(parser(Partial::new("S")), Err(ErrMode::Backtrack(InputError::new(Partial::new("S"), ErrorKind::Tag)))); /// assert_eq!(parser(Partial::new("H")), Err(ErrMode::Incomplete(Needed::new(4)))); /// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::token::tag; +/// use winnow::ascii::Caseless; +/// +/// fn parser(s: &str) -> IResult<&str, &str> { +/// tag(Caseless("hello")).parse_peek(s) +/// } +/// +/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); +/// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); +/// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); +/// assert_eq!(parser("Something"), Err(ErrMode::Backtrack(InputError::new("Something", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag)))); +/// ``` #[inline(always)] #[doc(alias = "literal")] #[doc(alias = "bytes")] @@ -201,6 +218,7 @@ where #[doc(alias = "literal")] #[doc(alias = "bytes")] #[doc(alias = "just")] +#[deprecated(since = "0.5.20", note = "Replaced with `tag(ascii::Caseless(_))`")] pub fn tag_no_case<T, I, Error: ParserError<I>>( tag: T, ) -> impl Parser<I, <I as Stream>::Slice, Error> @@ -219,6 +237,7 @@ where }) } +#[allow(deprecated)] fn tag_no_case_<T, I, Error: ParserError<I>, const PARTIAL: bool>( i: &mut I, t: T, @@ -244,7 +263,7 @@ where /// Recognize a token that matches the [pattern][ContainsToken] /// -/// **Note:** [`Parser`][crate::Parser] is implemented as a convenience (complete +/// **Note:** [`Parser`] is implemented as a convenience (complete /// only) for /// - `u8` /// - `char` @@ -349,9 +368,9 @@ where /// It will return an `ErrMode::Backtrack(InputError::new(_, ErrorKind::Slice))` if the pattern wasn't met or is out /// of range (m <= len <= n). /// -/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input or is too short. +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input or is too short. /// -/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. +/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`]. /// /// # Example /// @@ -546,14 +565,27 @@ where I: Stream, T: ContainsToken<<I as Stream>::Token>, { - let e: ErrorKind = ErrorKind::Slice; if PARTIAL && input.is_partial() { - take_till1_partial(input, |c| !list.contains_token(c), e) + take_till1_partial(input, |c| !list.contains_token(c)) } else { - take_till1_complete(input, |c| !list.contains_token(c), e) + take_till1_complete(input, |c| !list.contains_token(c)) } } +fn take_while_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>( + input: &mut I, + m: usize, + n: usize, + list: &T, +) -> PResult<<I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + take_till_m_n::<_, _, _, PARTIAL>(input, m, n, |c| !list.contains_token(c)) +} + /// Looks for the first element of the input type for which the condition returns true, /// and returns the input up to this position. /// @@ -580,11 +612,11 @@ where fn take_till1_partial<P, I: Stream, E: ParserError<I>>( input: &mut I, predicate: P, - e: ErrorKind, ) -> PResult<<I as Stream>::Slice, E> where P: Fn(I::Token) -> bool, { + let e: ErrorKind = ErrorKind::Slice; let offset = input .offset_for(predicate) .ok_or_else(|| ErrMode::Incomplete(Needed::new(1)))?; @@ -621,11 +653,11 @@ where fn take_till1_complete<P, I: Stream, E: ParserError<I>>( input: &mut I, predicate: P, - e: ErrorKind, ) -> PResult<<I as Stream>::Slice, E> where P: Fn(I::Token) -> bool, { + let e: ErrorKind = ErrorKind::Slice; let offset = input .offset_for(predicate) .unwrap_or_else(|| input.eof_offset()); @@ -636,16 +668,16 @@ where } } -fn take_while_m_n_<T, I, Error: ParserError<I>, const PARTIAL: bool>( +fn take_till_m_n<P, I, Error: ParserError<I>, const PARTIAL: bool>( input: &mut I, m: usize, n: usize, - list: &T, + predicate: P, ) -> PResult<<I as Stream>::Slice, Error> where I: StreamIsPartial, I: Stream, - T: ContainsToken<<I as Stream>::Token>, + P: Fn(I::Token) -> bool, { if n < m { return Err(ErrMode::assert(input, "`m` should be <= `n`")); @@ -653,7 +685,7 @@ where let mut final_count = 0; for (processed, (offset, token)) in input.iter_offsets().enumerate() { - if !list.contains_token(token) { + if predicate(token) { if processed < m { return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); } else { @@ -696,6 +728,86 @@ where /// ```rust /// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed}; /// # use winnow::prelude::*; +/// use winnow::token::take_till; +/// +/// fn till_colon(s: &str) -> IResult<&str, &str> { +/// take_till(0.., |c| c == ':').parse_peek(s) +/// } +/// +/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); +/// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed +/// assert_eq!(till_colon("12345"), Ok(("", "12345"))); +/// assert_eq!(till_colon(""), Ok(("", ""))); +/// ``` +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed}; +/// # use winnow::prelude::*; +/// # use winnow::Partial; +/// use winnow::token::take_till; +/// +/// fn till_colon(s: Partial<&str>) -> IResult<Partial<&str>, &str> { +/// take_till(0.., |c| c == ':').parse_peek(s) +/// } +/// +/// assert_eq!(till_colon(Partial::new("latin:123")), Ok((Partial::new(":123"), "latin"))); +/// assert_eq!(till_colon(Partial::new(":empty matched")), Ok((Partial::new(":empty matched"), ""))); //allowed +/// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); +/// ``` +#[inline(always)] +#[doc(alias = "is_not")] +pub fn take_till<T, I, Error: ParserError<I>>( + range: impl Into<Range>, + list: T, +) -> impl Parser<I, <I as Stream>::Slice, Error> +where + I: StreamIsPartial, + I: Stream, + T: ContainsToken<<I as Stream>::Token>, +{ + let Range { + start_inclusive, + end_inclusive, + } = range.into(); + trace("take_till", move |i: &mut I| { + match (start_inclusive, end_inclusive) { + (0, None) => { + if <I as StreamIsPartial>::is_partial_supported() { + take_till0_partial(i, |c| list.contains_token(c)) + } else { + take_till0_complete(i, |c| list.contains_token(c)) + } + } + (1, None) => { + if <I as StreamIsPartial>::is_partial_supported() { + take_till1_partial(i, |c| list.contains_token(c)) + } else { + take_till1_complete(i, |c| list.contains_token(c)) + } + } + (start, end) => { + let end = end.unwrap_or(usize::MAX); + if <I as StreamIsPartial>::is_partial_supported() { + take_till_m_n::<_, _, _, true>(i, start, end, |c| list.contains_token(c)) + } else { + take_till_m_n::<_, _, _, false>(i, start, end, |c| list.contains_token(c)) + } + } + } + }) +} + +/// Recognize the longest input slice (if any) till a [pattern][ContainsToken] is met. +/// +/// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` if the match reaches the +/// end of input or if there was not match. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::ErrorKind, error::InputError, error::Needed}; +/// # use winnow::prelude::*; /// use winnow::token::take_till0; /// /// fn till_colon(s: &str) -> IResult<&str, &str> { @@ -723,6 +835,7 @@ where /// assert_eq!(till_colon(Partial::new("12345")), Err(ErrMode::Incomplete(Needed::new(1)))); /// assert_eq!(till_colon(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); /// ``` +#[deprecated(since = "0.5.21", note = "Replaced with `take_till(0.., ...)`")] #[inline(always)] pub fn take_till0<T, I, Error: ParserError<I>>( list: T, @@ -800,7 +913,7 @@ where /// assert_eq!(not_space(Partial::new("")), Err(ErrMode::Incomplete(Needed::new(1)))); /// ``` #[inline(always)] -#[doc(alias = "is_not")] +#[deprecated(since = "0.5.21", note = "Replaced with `take_till(1.., ...)`")] pub fn take_till1<T, I, Error: ParserError<I>>( list: T, ) -> impl Parser<I, <I as Stream>::Slice, Error> @@ -810,11 +923,10 @@ where T: ContainsToken<<I as Stream>::Token>, { trace("take_till1", move |i: &mut I| { - let e: ErrorKind = ErrorKind::Slice; if <I as StreamIsPartial>::is_partial_supported() && i.is_partial() { - take_till1_partial(i, |c| list.contains_token(c), e) + take_till1_partial(i, |c| list.contains_token(c)) } else { - take_till1_complete(i, |c| list.contains_token(c), e) + take_till1_complete(i, |c| list.contains_token(c)) } }) } @@ -1025,7 +1137,7 @@ where /// assert_eq!(until_eof(Partial::new("hello, world")), Err(ErrMode::Incomplete(Needed::Unknown))); /// assert_eq!(until_eof(Partial::new("hello, worldeo")), Err(ErrMode::Incomplete(Needed::Unknown))); /// assert_eq!(until_eof(Partial::new("1eof2eof")), Ok((Partial::new("eof2eof"), "1"))); -/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(InputError::new(Partial::new("eof"), ErrorKind::Slice)))); +/// assert_eq!(until_eof(Partial::new("eof")), Err(ErrMode::Backtrack(InputError::new(Partial::new("eof"), ErrorKind::Slice)))); /// ``` #[inline(always)] pub fn take_until1<T, I, Error: ParserError<I>>( diff --git a/vendor/winnow/src/token/tests.rs b/vendor/winnow/src/token/tests.rs index d9f364607..696187d64 100644 --- a/vendor/winnow/src/token/tests.rs +++ b/vendor/winnow/src/token/tests.rs @@ -3,6 +3,7 @@ use super::*; #[cfg(feature = "std")] use proptest::prelude::*; +use crate::ascii::Caseless; use crate::binary::length_data; use crate::combinator::delimited; use crate::error::ErrMode; @@ -183,7 +184,7 @@ fn partial_is_a() { #[test] fn partial_is_not() { fn a_or_b(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { - take_till1(['a', 'b']).parse_peek(i) + take_till(1.., ['a', 'b']).parse_peek(i) } let a = Partial::new(&b"cdab"[..]); @@ -365,7 +366,7 @@ fn partial_take_while_m_n() { #[test] fn partial_take_till0() { fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { - take_till0(AsChar::is_alpha).parse_peek(i) + take_till(0.., AsChar::is_alpha).parse_peek(i) } let a = &b""[..]; let b = &b"abcd"[..]; @@ -387,7 +388,7 @@ fn partial_take_till0() { #[test] fn partial_take_till1() { fn f(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { - take_till1(AsChar::is_alpha).parse_peek(i) + take_till(1.., AsChar::is_alpha).parse_peek(i) } let a = &b""[..]; let b = &b"abcd"[..]; @@ -447,7 +448,7 @@ fn partial_take_while_utf8() { #[test] fn partial_take_till0_utf8() { fn f(i: Partial<&str>) -> IResult<Partial<&str>, &str> { - take_till0(|c| c == '點').parse_peek(i) + take_till(0.., |c| c == '點').parse_peek(i) } assert_eq!( @@ -465,7 +466,7 @@ fn partial_take_till0_utf8() { ); fn g(i: Partial<&str>) -> IResult<Partial<&str>, &str> { - take_till0(|c| c != '點').parse_peek(i) + take_till(0.., |c| c != '點').parse_peek(i) } assert_eq!( @@ -619,7 +620,7 @@ fn partial_length_bytes() { #[test] fn partial_case_insensitive() { fn test(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, &[u8]> { - tag_no_case("ABcd").parse_peek(i) + tag(Caseless("ABcd")).parse_peek(i) } assert_eq!( test(Partial::new(&b"aBCdefgh"[..])), @@ -653,7 +654,7 @@ fn partial_case_insensitive() { ); fn test2(i: Partial<&str>) -> IResult<Partial<&str>, &str> { - tag_no_case("ABcd").parse_peek(i) + tag(Caseless("ABcd")).parse_peek(i) } assert_eq!( test2(Partial::new("aBCdefgh")), diff --git a/vendor/winnow/src/trace/mod.rs b/vendor/winnow/src/trace/mod.rs index cd96e0258..6fe89aca2 100644 --- a/vendor/winnow/src/trace/mod.rs +++ b/vendor/winnow/src/trace/mod.rs @@ -1,11 +1,12 @@ //! Parser execution tracing //! -//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use +//! By default, nothing happens and tracing gets compiled away as a no-op. To enable tracing, use //! `--features debug`. //! //! # Example //! //!![Trace output from string example](https://raw.githubusercontent.com/winnow-rs/winnow/main/assets/trace.svg "Example output") +#![cfg_attr(feature = "debug", allow(clippy::std_instead_of_core))] #[cfg(feature = "debug")] mod internals; @@ -19,7 +20,7 @@ compile_error!("`debug` requires `std`"); /// Trace the execution of the parser /// -/// Note that [`Parser::context` also provides high level trace information. +/// Note that [`Parser::context`] also provides high level trace information. /// /// See [`trace` module][self] for more details. /// |