From 8cdfa445d6629ffef4cb84967ff7017654045bc2 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 18:36:06 -0600 Subject: chore: add vendor directory --- vendor/prettyplease/.cargo-checksum.json | 1 + vendor/prettyplease/Cargo.lock | 54 + vendor/prettyplease/Cargo.toml | 90 + vendor/prettyplease/LICENSE-APACHE | 176 ++ vendor/prettyplease/LICENSE-MIT | 23 + vendor/prettyplease/README.md | 312 ++++ vendor/prettyplease/build.rs | 21 + vendor/prettyplease/examples/input.rs | 1 + .../prettyplease/examples/output.prettyplease.rs | 593 +++++++ vendor/prettyplease/examples/output.rustc.rs | 506 ++++++ vendor/prettyplease/examples/output.rustfmt.rs | 552 ++++++ vendor/prettyplease/src/algorithm.rs | 386 +++++ vendor/prettyplease/src/attr.rs | 288 ++++ vendor/prettyplease/src/classify.rs | 324 ++++ vendor/prettyplease/src/convenience.rs | 98 ++ vendor/prettyplease/src/data.rs | 79 + vendor/prettyplease/src/expr.rs | 1533 +++++++++++++++++ vendor/prettyplease/src/file.rs | 17 + vendor/prettyplease/src/fixup.rs | 676 ++++++++ vendor/prettyplease/src/generics.rs | 383 +++++ vendor/prettyplease/src/item.rs | 1812 ++++++++++++++++++++ vendor/prettyplease/src/iter.rs | 46 + vendor/prettyplease/src/lib.rs | 385 +++++ vendor/prettyplease/src/lifetime.rs | 9 + vendor/prettyplease/src/lit.rs | 57 + vendor/prettyplease/src/mac.rs | 706 ++++++++ vendor/prettyplease/src/pat.rs | 254 +++ vendor/prettyplease/src/path.rs | 194 +++ vendor/prettyplease/src/precedence.rs | 148 ++ vendor/prettyplease/src/ring.rs | 81 + vendor/prettyplease/src/stmt.rs | 221 +++ vendor/prettyplease/src/token.rs | 80 + vendor/prettyplease/src/ty.rs | 339 ++++ vendor/prettyplease/tests/test.rs | 51 + vendor/prettyplease/tests/test_precedence.rs | 900 ++++++++++ 35 files changed, 11396 insertions(+) create mode 100644 vendor/prettyplease/.cargo-checksum.json create mode 100644 vendor/prettyplease/Cargo.lock create mode 100644 vendor/prettyplease/Cargo.toml create mode 100644 vendor/prettyplease/LICENSE-APACHE create mode 100644 vendor/prettyplease/LICENSE-MIT create mode 100644 vendor/prettyplease/README.md create mode 100644 vendor/prettyplease/build.rs create mode 100644 vendor/prettyplease/examples/input.rs create mode 100644 vendor/prettyplease/examples/output.prettyplease.rs create mode 100644 vendor/prettyplease/examples/output.rustc.rs create mode 100644 vendor/prettyplease/examples/output.rustfmt.rs create mode 100644 vendor/prettyplease/src/algorithm.rs create mode 100644 vendor/prettyplease/src/attr.rs create mode 100644 vendor/prettyplease/src/classify.rs create mode 100644 vendor/prettyplease/src/convenience.rs create mode 100644 vendor/prettyplease/src/data.rs create mode 100644 vendor/prettyplease/src/expr.rs create mode 100644 vendor/prettyplease/src/file.rs create mode 100644 vendor/prettyplease/src/fixup.rs create mode 100644 vendor/prettyplease/src/generics.rs create mode 100644 vendor/prettyplease/src/item.rs create mode 100644 vendor/prettyplease/src/iter.rs create mode 100644 vendor/prettyplease/src/lib.rs create mode 100644 vendor/prettyplease/src/lifetime.rs create mode 100644 vendor/prettyplease/src/lit.rs create mode 100644 vendor/prettyplease/src/mac.rs create mode 100644 vendor/prettyplease/src/pat.rs create mode 100644 vendor/prettyplease/src/path.rs create mode 100644 vendor/prettyplease/src/precedence.rs create mode 100644 vendor/prettyplease/src/ring.rs create mode 100644 vendor/prettyplease/src/stmt.rs create mode 100644 vendor/prettyplease/src/token.rs create mode 100644 vendor/prettyplease/src/ty.rs create mode 100644 vendor/prettyplease/tests/test.rs create mode 100644 vendor/prettyplease/tests/test_precedence.rs (limited to 'vendor/prettyplease') diff --git a/vendor/prettyplease/.cargo-checksum.json b/vendor/prettyplease/.cargo-checksum.json new file mode 100644 index 00000000..9f67b4e1 --- /dev/null +++ b/vendor/prettyplease/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"8cf7ad35d2a8f934f2c502eda7b1977ed87bd2bad0b3714fbb6b3a725dacfa27","Cargo.toml":"bf31ddfd1c5e933cde148be0b08937b8d965da3e2cd9422e0ff06e878b8e7ade","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"a7e6d152cdc6ea603077e50b8d55af374d9d21fd9f62d08a008588b17d785e6e","build.rs":"79a5b2d260aa97aeac7105fbfa00774982f825cd708c100ea96d01c39974bb88","examples/input.rs":"53350088f12a346a99034af41ef432dedcc9e5d581c5592d9aae3807c42656c1","examples/output.prettyplease.rs":"fa63c118daadb64c456ec5b8d5e46e5d7fabbbeb6a6e61a08eabc23360a18fbd","examples/output.rustc.rs":"04647e9b01f2aa85982f849c2d897acf3b6931121c1ef953de5fb6a67b80e05a","examples/output.rustfmt.rs":"914a9aea1c51e097bfd80c9af4011811e6126c9df5fb0eac3d40b1203fba7c58","src/algorithm.rs":"901c91416d7526038bfad30e0066295a03d2bb995830016ace49a41540079010","src/attr.rs":"0a5c64b1c1f6fe4944c1d805c528ee4a9a8c6223e875afe9f48371cba66732ee","src/classify.rs":"2ce2d63ad9071aac10b1037e6382703736e0147d96b3ccf32a53182d12883f1b","src/convenience.rs":"dd392b009b691d3587c7d8e3caeaacf450303c4223792b5f89c336358e371c39","src/data.rs":"5bc2dce1cfa1aa5c1324ccdc2d76a6bd5df2382530c7e863d2bb50dea60cc4bc","src/expr.rs":"c73157238a80b0fb9a1949c6250cbb01f2df9217770f263dffcf5e5fbb570296","src/file.rs":"5689efa3c5959a6a0d8cfc2c13bf8a37ab0669e2b81dbded3f3c28884a88fca0","src/fixup.rs":"ecf87543c342fffc79bae54e4fa174cbfd5c341817315caa3b95cce0d49ebf7c","src/generics.rs":"f10b95f4b011f5bf6510d3a77e38227716dccf0a8aeb8a8344e776be9f90f54e","src/item.rs":"4dc320bf73f4ca7d2c6741c31700b5150a02106bfe688969070aff53c2ce455a","src/iter.rs":"38b2cd3b38719c6024fb6b3aa739f6f8736c83193fd21e2365d4f6c27bc41666","src/lib.rs":"4ab10c35515b340eed4fbdfc901a20d8432a1fd19734124b392ce4b2011c4f63","src/lifetime.rs":"6d420430168185b2da3409bc38a45f63cced9443915f04e6aec71367fc070dcf","src/lit.rs":"9ea6d25533e64df4ff01c084fa1c31ddf64fb3b159409eec7d80dbf281e5171e","src/mac.rs":"c1f8f9d60a6d116a63a7aa86d3dafdc5279c030b7f6a3e9bf119df109a913c8e","src/pat.rs":"8e53fd1b5382bb068210162bfab9921246093cfdd80dd93cd8627fcfdae39940","src/path.rs":"e73d83dc38f5c6c0c82f824da7eb090a16027f32fc40446b185580ee5e99be58","src/precedence.rs":"a8ce97ba0a25f442b5f238c64f078d70f4114b4b0f9df82764d533dd39a47abb","src/ring.rs":"517b1a02f8e0a9c1316830117daad1e30d17e1fcf6428c6b438c626aa43286ae","src/stmt.rs":"e17ab9647fed9daa4f5b2fbd007015128f2a7fc65686a988593444a37242f885","src/token.rs":"c288b1d81f2a35673d4ca1dd10d3386670b067460121df3038303e1ed73b41a7","src/ty.rs":"a1e3e5a08124673826948f97e70c11800081d2bca7f3aec12d84d0d00837290f","tests/test.rs":"c6f8c7830b7491fca1d56e41aa4acc6256b683a3556a48982f57ae62d38aaaa2","tests/test_precedence.rs":"de0c770b9a72e5eba8a52dcac0614d6db8ff5041ba601e1e67f113d68c9afd50"},"package":"061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"} \ No newline at end of file diff --git a/vendor/prettyplease/Cargo.lock b/vendor/prettyplease/Cargo.lock new file mode 100644 index 00000000..e1d60638 --- /dev/null +++ b/vendor/prettyplease/Cargo.lock @@ -0,0 +1,54 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "prettyplease" +version = "0.2.35" +dependencies = [ + "indoc", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/vendor/prettyplease/Cargo.toml b/vendor/prettyplease/Cargo.toml new file mode 100644 index 00000000..721d34b2 --- /dev/null +++ b/vendor/prettyplease/Cargo.toml @@ -0,0 +1,90 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.62" +name = "prettyplease" +version = "0.2.35" +authors = ["David Tolnay "] +build = "build.rs" +links = "prettyplease02" +exclude = ["cargo-expand"] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A minimal `syn` syntax tree pretty-printer" +documentation = "https://docs.rs/prettyplease" +readme = "README.md" +keywords = ["rustfmt"] +categories = ["development-tools"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/prettyplease" + +[package.metadata.docs.rs] +rustdoc-args = [ + "--generate-link-to-definition", + "--extern-html-root-url=core=https://doc.rust-lang.org", + "--extern-html-root-url=alloc=https://doc.rust-lang.org", + "--extern-html-root-url=std=https://doc.rust-lang.org", +] +targets = ["x86_64-unknown-linux-gnu"] + +[package.metadata.playground] +features = ["verbatim"] + +[features] +verbatim = ["syn/parsing"] + +[lib] +name = "prettyplease" +path = "src/lib.rs" + +[[test]] +name = "test" +path = "tests/test.rs" + +[[test]] +name = "test_precedence" +path = "tests/test_precedence.rs" + +[dependencies.proc-macro2] +version = "1.0.80" +default-features = false + +[dependencies.syn] +version = "2.0.104" +features = ["full"] +default-features = false + +[dev-dependencies.indoc] +version = "2" + +[dev-dependencies.proc-macro2] +version = "1.0.80" +default-features = false + +[dev-dependencies.quote] +version = "1.0.35" +default-features = false + +[dev-dependencies.syn] +version = "2.0.104" +features = [ + "clone-impls", + "extra-traits", + "parsing", + "printing", + "visit-mut", +] +default-features = false diff --git a/vendor/prettyplease/LICENSE-APACHE b/vendor/prettyplease/LICENSE-APACHE new file mode 100644 index 00000000..1b5ec8b7 --- /dev/null +++ b/vendor/prettyplease/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/vendor/prettyplease/LICENSE-MIT b/vendor/prettyplease/LICENSE-MIT new file mode 100644 index 00000000..31aa7938 --- /dev/null +++ b/vendor/prettyplease/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/prettyplease/README.md b/vendor/prettyplease/README.md new file mode 100644 index 00000000..4584c485 --- /dev/null +++ b/vendor/prettyplease/README.md @@ -0,0 +1,312 @@ +prettyplease::unparse +===================== + +[github](https://github.com/dtolnay/prettyplease) +[crates.io](https://crates.io/crates/prettyplease) +[docs.rs](https://docs.rs/prettyplease) +[build status](https://github.com/dtolnay/prettyplease/actions?query=branch%3Amaster) + +A minimal `syn` syntax tree pretty-printer. + +
+ +## Overview + +This is a pretty-printer to turn a `syn` syntax tree into a `String` of +well-formatted source code. In contrast to rustfmt, this library is intended to +be suitable for arbitrary generated code. + +Rustfmt prioritizes high-quality output that is impeccable enough that you'd be +comfortable spending your career staring at its output — but that means +some heavyweight algorithms, and it has a tendency to bail out on code that is +hard to format (for example [rustfmt#3697], and there are dozens more issues +like it). That's not necessarily a big deal for human-generated code because +when code gets highly nested, the human will naturally be inclined to refactor +into more easily formattable code. But for generated code, having the formatter +just give up leaves it totally unreadable. + +[rustfmt#3697]: https://github.com/rust-lang/rustfmt/issues/3697 + +This library is designed using the simplest possible algorithm and data +structures that can deliver about 95% of the quality of rustfmt-formatted +output. In my experience testing real-world code, approximately 97-98% of output +lines come out identical between rustfmt's formatting and this crate's. The rest +have slightly different linebreak decisions, but still clearly follow the +dominant modern Rust style. + +The tradeoffs made by this crate are a good fit for generated code that you will +*not* spend your career staring at. For example, the output of `bindgen`, or the +output of `cargo-expand`. In those cases it's more important that the whole +thing be formattable without the formatter giving up, than that it be flawless. + +
+ +## Feature matrix + +Here are a few superficial comparisons of this crate against the AST +pretty-printer built into rustc, and rustfmt. The sections below go into more +detail comparing the output of each of these libraries. + +| | prettyplease | rustc | rustfmt | +|:---|:---:|:---:|:---:| +| non-pathological behavior on big or generated code | 💚 | ❌ | ❌ | +| idiomatic modern formatting ("locally indistinguishable from rustfmt") | 💚 | ❌ | 💚 | +| throughput | 60 MB/s | 39 MB/s | 2.8 MB/s | +| number of dependencies | 3 | 72 | 66 | +| compile time including dependencies | 2.4 sec | 23.1 sec | 29.8 sec | +| buildable using a stable Rust compiler | 💚 | ❌ | ❌ | +| published to crates.io | 💚 | ❌ | ❌ | +| extensively configurable output | ❌ | ❌ | 💚 | +| intended to accommodate hand-maintained source code | ❌ | ❌ | 💚 | + +
+ +## Comparison to rustfmt + +- [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) +- [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) +- [output.rustfmt.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustfmt.rs) + +If you weren't told which output file is which, it would be practically +impossible to tell — **except** for line 435 in the rustfmt output, which +is more than 1000 characters long because rustfmt just gave up formatting that +part of the file: + +```rust + match segments[5] { + 0 => write!(f, "::{}", ipv4), + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } + } else { + const IPV6_BUF_LEN: usize = (4 * 8) + 7; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; +``` + +This is a pretty typical manifestation of rustfmt bailing out in generated code +— a chunk of the input ends up on one line. The other manifestation is +that you're working on some code, running rustfmt on save like a conscientious +developer, but after a while notice it isn't doing anything. You introduce an +intentional formatting issue, like a stray indent or semicolon, and run rustfmt +to check your suspicion. Nope, it doesn't get cleaned up — rustfmt is just +not formatting the part of the file you are working on. + +The prettyplease library is designed to have no pathological cases that force a +bail out; the entire input you give it will get formatted in some "good enough" +form. + +Separately, rustfmt can be problematic to integrate into projects. It's written +using rustc's internal syntax tree, so it can't be built by a stable compiler. +Its releases are not regularly published to crates.io, so in Cargo builds you'd +need to depend on it as a git dependency, which precludes publishing your crate +to crates.io also. You can shell out to a `rustfmt` binary, but that'll be +whatever rustfmt version is installed on each developer's system (if any), which +can lead to spurious diffs in checked-in generated code formatted by different +versions. In contrast prettyplease is designed to be easy to pull in as a +library, and compiles fast. + +
+ +## Comparison to rustc_ast_pretty + +- [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) +- [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) +- [output.rustc.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustc.rs) + +This is the pretty-printer that gets used when rustc prints source code, such as +`rustc -Zunpretty=expanded`. It's used also by the standard library's +`stringify!` when stringifying an interpolated macro_rules AST fragment, like an +$:expr, and transitively by `dbg!` and many macros in the ecosystem. + +Rustc's formatting is mostly okay, but does not hew closely to the dominant +contemporary style of Rust formatting. Some things wouldn't ever be written on +one line, like this `match` expression, and certainly not with a comma in front +of the closing brace: + +```rust +fn eq(&self, other: &IpAddr) -> bool { + match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } +} +``` + +Some places use non-multiple-of-4 indentation, which is definitely not the norm: + +```rust +pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr{inner: + c::in6_addr{s6_addr: + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, + 0xFF, a, b, c, d],},} +} +``` + +And although there isn't an egregious example of it in the link because the +input code is pretty tame, in general rustc_ast_pretty has pathological behavior +on generated code. It has a tendency to use excessive horizontal indentation and +rapidly run out of width: + +```rust +::std::io::_print(::core::fmt::Arguments::new_v1(&[""], + &match (&msg,) { + _args => + [::core::fmt::ArgumentV1::new(_args.0, + ::core::fmt::Display::fmt)], + })); +``` + +The snippets above are clearly different from modern rustfmt style. In contrast, +prettyplease is designed to have output that is practically indistinguishable +from rustfmt-formatted code. + +
+ +## Example + +```rust +// [dependencies] +// prettyplease = "0.2" +// syn = { version = "2", default-features = false, features = ["full", "parsing"] } + +const INPUT: &str = stringify! { + use crate::{ + lazy::{Lazy, SyncLazy, SyncOnceCell}, panic, + sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, + mpsc::channel, Mutex, }, + thread, + }; + impl Into for T where U: From { + fn into(self) -> U { U::from(self) } + } +}; + +fn main() { + let syntax_tree = syn::parse_file(INPUT).unwrap(); + let formatted = prettyplease::unparse(&syntax_tree); + print!("{}", formatted); +} +``` + +
+ +## Algorithm notes + +The approach and terminology used in the implementation are derived from [*Derek +C. Oppen, "Pretty Printing" (1979)*][paper], on which rustc_ast_pretty is also +based, and from rustc_ast_pretty's implementation written by Graydon Hoare in +2011 (and modernized over the years by dozens of volunteer maintainers). + +[paper]: http://i.stanford.edu/pub/cstr/reports/cs/tr/79/770/CS-TR-79-770.pdf + +The paper describes two language-agnostic interacting procedures `Scan()` and +`Print()`. Language-specific code decomposes an input data structure into a +stream of `string` and `break` tokens, and `begin` and `end` tokens for +grouping. Each `begin`–`end` range may be identified as either "consistent +breaking" or "inconsistent breaking". If a group is consistently breaking, then +if the whole contents do not fit on the line, *every* `break` token in the group +will receive a linebreak. This is appropriate, for example, for Rust struct +literals, or arguments of a function call. If a group is inconsistently +breaking, then the `string` tokens in the group are greedily placed on the line +until out of space, and linebroken only at those `break` tokens for which the +next string would not fit. For example, this is appropriate for the contents of +a braced `use` statement in Rust. + +Scan's job is to efficiently accumulate sizing information about groups and +breaks. For every `begin` token we compute the distance to the matched `end` +token, and for every `break` we compute the distance to the next `break`. The +algorithm uses a ringbuffer to hold tokens whose size is not yet ascertained. +The maximum size of the ringbuffer is bounded by the target line length and does +not grow indefinitely, regardless of deep nesting in the input stream. That's +because once a group is sufficiently big, the precise size can no longer make a +difference to linebreak decisions and we can effectively treat it as "infinity". + +Print's job is to use the sizing information to efficiently assign a "broken" or +"not broken" status to every `begin` token. At that point the output is easily +constructed by concatenating `string` tokens and breaking at `break` tokens +contained within a broken group. + +Leveraging these primitives (i.e. cleverly placing the all-or-nothing consistent +breaks and greedy inconsistent breaks) to yield rustfmt-compatible formatting +for all of Rust's syntax tree nodes is a fun challenge. + +Here is a visualization of some Rust tokens fed into the pretty printing +algorithm. Consistently breaking `begin`—`end` pairs are represented by +`«`⁠`»`, inconsistently breaking by `‹`⁠`›`, `break` by `·`, and the +rest of the non-whitespace are `string`. + +```text +use crate::«{· +‹ lazy::«{·‹Lazy,· SyncLazy,· SyncOnceCell›·}»,· + panic,· + sync::«{· +‹ atomic::«{·‹AtomicUsize,· Ordering::SeqCst›·}»,· + mpsc::channel,· Mutex›,· + }»,· + thread›,· +}»;· +«‹«impl<«·T‹›,· U‹›·»>» Into<«·U·»>· for T›· +where· + U:‹ From<«·T·»>›,· +{· +« fn into(·«·self·») -> U {· +‹ U::from(«·self·»)›· +» }· +»}· +``` + +The algorithm described in the paper is not quite sufficient for producing +well-formatted Rust code that is locally indistinguishable from rustfmt's style. +The reason is that in the paper, the complete non-whitespace contents are +assumed to be independent of linebreak decisions, with Scan and Print being only +in control of the whitespace (spaces and line breaks). In Rust as idiomatically +formatted by rustfmt, that is not the case. Trailing commas are one example; the +punctuation is only known *after* the broken vs non-broken status of the +surrounding group is known: + +```rust +let _ = Struct { x: 0, y: true }; + +let _ = Struct { + x: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, + y: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy, //<- trailing comma if the expression wrapped +}; +``` + +The formatting of `match` expressions is another case; we want small arms on the +same line as the pattern, and big arms wrapped in a brace. The presence of the +brace punctuation, comma, and semicolon are all dependent on whether the arm +fits on the line: + +```rust +match total_nanos.checked_add(entry.nanos as u64) { + Some(n) => tmp = n, //<- small arm, inline with comma + None => { + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + } //<- big arm, needs brace added, and also semicolon^ +} +``` + +The printing algorithm implementation in this crate accommodates all of these +situations with conditional punctuation tokens whose selection can be deferred +and populated after it's known that the group is or is not broken. + +
+ +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/vendor/prettyplease/build.rs b/vendor/prettyplease/build.rs new file mode 100644 index 00000000..4fc36f74 --- /dev/null +++ b/vendor/prettyplease/build.rs @@ -0,0 +1,21 @@ +use std::env; +use std::ffi::OsString; +use std::process; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + println!("cargo:rustc-check-cfg=cfg(exhaustive)"); + println!("cargo:rustc-check-cfg=cfg(prettyplease_debug)"); + println!("cargo:rustc-check-cfg=cfg(prettyplease_debug_indent)"); + + let pkg_version = cargo_env_var("CARGO_PKG_VERSION"); + println!("cargo:VERSION={}", pkg_version.to_str().unwrap()); +} + +fn cargo_env_var(key: &str) -> OsString { + env::var_os(key).unwrap_or_else(|| { + eprintln!("Environment variable ${key} is not set during execution of build script"); + process::exit(1); + }) +} diff --git a/vendor/prettyplease/examples/input.rs b/vendor/prettyplease/examples/input.rs new file mode 100644 index 00000000..ca3d9803 --- /dev/null +++ b/vendor/prettyplease/examples/input.rs @@ -0,0 +1 @@ +use crate :: cmp :: Ordering ; use crate :: fmt :: { self , Write as FmtWrite } ; use crate :: hash ; use crate :: io :: Write as IoWrite ; use crate :: mem :: transmute ; use crate :: sys :: net :: netc as c ; use crate :: sys_common :: { AsInner , FromInner , IntoInner } ; # [derive (Copy , Clone , Eq , PartialEq , Hash , PartialOrd , Ord)] pub enum IpAddr { V4 (Ipv4Addr) , V6 (Ipv6Addr) , } # [derive (Copy)] pub struct Ipv4Addr { inner : c :: in_addr , } # [derive (Copy)] pub struct Ipv6Addr { inner : c :: in6_addr , } # [derive (Copy , PartialEq , Eq , Clone , Hash , Debug)] # [non_exhaustive] pub enum Ipv6MulticastScope { InterfaceLocal , LinkLocal , RealmLocal , AdminLocal , SiteLocal , OrganizationLocal , Global , } impl IpAddr { pub const fn is_unspecified (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_unspecified () , IpAddr :: V6 (ip) => ip . is_unspecified () , } } pub const fn is_loopback (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_loopback () , IpAddr :: V6 (ip) => ip . is_loopback () , } } pub const fn is_global (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_global () , IpAddr :: V6 (ip) => ip . is_global () , } } pub const fn is_multicast (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_multicast () , IpAddr :: V6 (ip) => ip . is_multicast () , } } pub const fn is_documentation (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_documentation () , IpAddr :: V6 (ip) => ip . is_documentation () , } } pub const fn is_benchmarking (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_benchmarking () , IpAddr :: V6 (ip) => ip . is_benchmarking () , } } pub const fn is_ipv4 (& self) -> bool { matches ! (self , IpAddr :: V4 (_)) } pub const fn is_ipv6 (& self) -> bool { matches ! (self , IpAddr :: V6 (_)) } pub const fn to_canonical (& self) -> IpAddr { match self { & v4 @ IpAddr :: V4 (_) => v4 , IpAddr :: V6 (v6) => v6 . to_canonical () , } } } impl Ipv4Addr { pub const fn new (a : u8 , b : u8 , c : u8 , d : u8) -> Ipv4Addr { Ipv4Addr { inner : c :: in_addr { s_addr : u32 :: from_ne_bytes ([a , b , c , d]) } } } pub const LOCALHOST : Self = Ipv4Addr :: new (127 , 0 , 0 , 1) ; # [doc (alias = "INADDR_ANY")] pub const UNSPECIFIED : Self = Ipv4Addr :: new (0 , 0 , 0 , 0) ; pub const BROADCAST : Self = Ipv4Addr :: new (255 , 255 , 255 , 255) ; pub const fn octets (& self) -> [u8 ; 4] { self . inner . s_addr . to_ne_bytes () } pub const fn is_unspecified (& self) -> bool { self . inner . s_addr == 0 } pub const fn is_loopback (& self) -> bool { self . octets () [0] == 127 } pub const fn is_private (& self) -> bool { match self . octets () { [10 , ..] => true , [172 , b , ..] if b >= 16 && b <= 31 => true , [192 , 168 , ..] => true , _ => false , } } pub const fn is_link_local (& self) -> bool { matches ! (self . octets () , [169 , 254 , ..]) } pub const fn is_global (& self) -> bool { if u32 :: from_be_bytes (self . octets ()) == 0xc0000009 || u32 :: from_be_bytes (self . octets ()) == 0xc000000a { return true ; } ! self . is_private () && ! self . is_loopback () && ! self . is_link_local () && ! self . is_broadcast () && ! self . is_documentation () && ! self . is_shared () && ! (self . octets () [0] == 192 && self . octets () [1] == 0 && self . octets () [2] == 0) && ! self . is_reserved () && ! self . is_benchmarking () && self . octets () [0] != 0 } pub const fn is_shared (& self) -> bool { self . octets () [0] == 100 && (self . octets () [1] & 0b1100_0000 == 0b0100_0000) } pub const fn is_benchmarking (& self) -> bool { self . octets () [0] == 198 && (self . octets () [1] & 0xfe) == 18 } pub const fn is_reserved (& self) -> bool { self . octets () [0] & 240 == 240 && ! self . is_broadcast () } pub const fn is_multicast (& self) -> bool { self . octets () [0] >= 224 && self . octets () [0] <= 239 } pub const fn is_broadcast (& self) -> bool { u32 :: from_be_bytes (self . octets ()) == u32 :: from_be_bytes (Self :: BROADCAST . octets ()) } pub const fn is_documentation (& self) -> bool { matches ! (self . octets () , [192 , 0 , 2 , _] | [198 , 51 , 100 , _] | [203 , 0 , 113 , _]) } pub const fn to_ipv6_compatible (& self) -> Ipv6Addr { let [a , b , c , d] = self . octets () ; Ipv6Addr { inner : c :: in6_addr { s6_addr : [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , a , b , c , d] } , } } pub const fn to_ipv6_mapped (& self) -> Ipv6Addr { let [a , b , c , d] = self . octets () ; Ipv6Addr { inner : c :: in6_addr { s6_addr : [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xFF , 0xFF , a , b , c , d] } , } } } impl fmt :: Display for IpAddr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { match self { IpAddr :: V4 (ip) => ip . fmt (fmt) , IpAddr :: V6 (ip) => ip . fmt (fmt) , } } } impl fmt :: Debug for IpAddr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl From < Ipv4Addr > for IpAddr { fn from (ipv4 : Ipv4Addr) -> IpAddr { IpAddr :: V4 (ipv4) } } impl From < Ipv6Addr > for IpAddr { fn from (ipv6 : Ipv6Addr) -> IpAddr { IpAddr :: V6 (ipv6) } } impl fmt :: Display for Ipv4Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { let octets = self . octets () ; if fmt . precision () . is_none () && fmt . width () . is_none () { write ! (fmt , "{}.{}.{}.{}" , octets [0] , octets [1] , octets [2] , octets [3]) } else { const IPV4_BUF_LEN : usize = 15 ; let mut buf = [0u8 ; IPV4_BUF_LEN] ; let mut buf_slice = & mut buf [..] ; write ! (buf_slice , "{}.{}.{}.{}" , octets [0] , octets [1] , octets [2] , octets [3]) . unwrap () ; let len = IPV4_BUF_LEN - buf_slice . len () ; let buf = unsafe { crate :: str :: from_utf8_unchecked (& buf [.. len]) } ; fmt . pad (buf) } } } impl fmt :: Debug for Ipv4Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl Clone for Ipv4Addr { fn clone (& self) -> Ipv4Addr { * self } } impl PartialEq for Ipv4Addr { fn eq (& self , other : & Ipv4Addr) -> bool { self . inner . s_addr == other . inner . s_addr } } impl PartialEq < Ipv4Addr > for IpAddr { fn eq (& self , other : & Ipv4Addr) -> bool { match self { IpAddr :: V4 (v4) => v4 == other , IpAddr :: V6 (_) => false , } } } impl PartialEq < IpAddr > for Ipv4Addr { fn eq (& self , other : & IpAddr) -> bool { match other { IpAddr :: V4 (v4) => self == v4 , IpAddr :: V6 (_) => false , } } } impl Eq for Ipv4Addr { } impl hash :: Hash for Ipv4Addr { fn hash < H : hash :: Hasher > (& self , s : & mut H) { { self . inner . s_addr } . hash (s) } } impl PartialOrd for Ipv4Addr { fn partial_cmp (& self , other : & Ipv4Addr) -> Option < Ordering > { Some (self . cmp (other)) } } impl PartialOrd < Ipv4Addr > for IpAddr { fn partial_cmp (& self , other : & Ipv4Addr) -> Option < Ordering > { match self { IpAddr :: V4 (v4) => v4 . partial_cmp (other) , IpAddr :: V6 (_) => Some (Ordering :: Greater) , } } } impl PartialOrd < IpAddr > for Ipv4Addr { fn partial_cmp (& self , other : & IpAddr) -> Option < Ordering > { match other { IpAddr :: V4 (v4) => self . partial_cmp (v4) , IpAddr :: V6 (_) => Some (Ordering :: Less) , } } } impl Ord for Ipv4Addr { fn cmp (& self , other : & Ipv4Addr) -> Ordering { u32 :: from_be (self . inner . s_addr) . cmp (& u32 :: from_be (other . inner . s_addr)) } } impl IntoInner < c :: in_addr > for Ipv4Addr { fn into_inner (self) -> c :: in_addr { self . inner } } impl From < Ipv4Addr > for u32 { fn from (ip : Ipv4Addr) -> u32 { let ip = ip . octets () ; u32 :: from_be_bytes (ip) } } impl From < u32 > for Ipv4Addr { fn from (ip : u32) -> Ipv4Addr { Ipv4Addr :: from (ip . to_be_bytes ()) } } impl From < [u8 ; 4] > for Ipv4Addr { fn from (octets : [u8 ; 4]) -> Ipv4Addr { Ipv4Addr :: new (octets [0] , octets [1] , octets [2] , octets [3]) } } impl From < [u8 ; 4] > for IpAddr { fn from (octets : [u8 ; 4]) -> IpAddr { IpAddr :: V4 (Ipv4Addr :: from (octets)) } } impl Ipv6Addr { pub const fn new (a : u16 , b : u16 , c : u16 , d : u16 , e : u16 , f : u16 , g : u16 , h : u16) -> Ipv6Addr { let addr16 = [a . to_be () , b . to_be () , c . to_be () , d . to_be () , e . to_be () , f . to_be () , g . to_be () , h . to_be () ,] ; Ipv6Addr { inner : c :: in6_addr { s6_addr : unsafe { transmute :: < _ , [u8 ; 16] > (addr16) } , } , } } pub const LOCALHOST : Self = Ipv6Addr :: new (0 , 0 , 0 , 0 , 0 , 0 , 0 , 1) ; pub const UNSPECIFIED : Self = Ipv6Addr :: new (0 , 0 , 0 , 0 , 0 , 0 , 0 , 0) ; pub const fn segments (& self) -> [u16 ; 8] { let [a , b , c , d , e , f , g , h] = unsafe { transmute :: < _ , [u16 ; 8] > (self . inner . s6_addr) } ; [u16 :: from_be (a) , u16 :: from_be (b) , u16 :: from_be (c) , u16 :: from_be (d) , u16 :: from_be (e) , u16 :: from_be (f) , u16 :: from_be (g) , u16 :: from_be (h) ,] } pub const fn is_unspecified (& self) -> bool { u128 :: from_be_bytes (self . octets ()) == u128 :: from_be_bytes (Ipv6Addr :: UNSPECIFIED . octets ()) } pub const fn is_loopback (& self) -> bool { u128 :: from_be_bytes (self . octets ()) == u128 :: from_be_bytes (Ipv6Addr :: LOCALHOST . octets ()) } pub const fn is_global (& self) -> bool { match self . multicast_scope () { Some (Ipv6MulticastScope :: Global) => true , None => self . is_unicast_global () , _ => false , } } pub const fn is_unique_local (& self) -> bool { (self . segments () [0] & 0xfe00) == 0xfc00 } pub const fn is_unicast (& self) -> bool { ! self . is_multicast () } pub const fn is_unicast_link_local (& self) -> bool { (self . segments () [0] & 0xffc0) == 0xfe80 } pub const fn is_documentation (& self) -> bool { (self . segments () [0] == 0x2001) && (self . segments () [1] == 0xdb8) } pub const fn is_benchmarking (& self) -> bool { (self . segments () [0] == 0x2001) && (self . segments () [1] == 0x2) && (self . segments () [2] == 0) } pub const fn is_unicast_global (& self) -> bool { self . is_unicast () && ! self . is_loopback () && ! self . is_unicast_link_local () && ! self . is_unique_local () && ! self . is_unspecified () && ! self . is_documentation () } pub const fn multicast_scope (& self) -> Option < Ipv6MulticastScope > { if self . is_multicast () { match self . segments () [0] & 0x000f { 1 => Some (Ipv6MulticastScope :: InterfaceLocal) , 2 => Some (Ipv6MulticastScope :: LinkLocal) , 3 => Some (Ipv6MulticastScope :: RealmLocal) , 4 => Some (Ipv6MulticastScope :: AdminLocal) , 5 => Some (Ipv6MulticastScope :: SiteLocal) , 8 => Some (Ipv6MulticastScope :: OrganizationLocal) , 14 => Some (Ipv6MulticastScope :: Global) , _ => None , } } else { None } } pub const fn is_multicast (& self) -> bool { (self . segments () [0] & 0xff00) == 0xff00 } pub const fn to_ipv4_mapped (& self) -> Option < Ipv4Addr > { match self . octets () { [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0xff , a , b , c , d] => { Some (Ipv4Addr :: new (a , b , c , d)) } _ => None , } } pub const fn to_ipv4 (& self) -> Option < Ipv4Addr > { if let [0 , 0 , 0 , 0 , 0 , 0 | 0xffff , ab , cd] = self . segments () { let [a , b] = ab . to_be_bytes () ; let [c , d] = cd . to_be_bytes () ; Some (Ipv4Addr :: new (a , b , c , d)) } else { None } } pub const fn to_canonical (& self) -> IpAddr { if let Some (mapped) = self . to_ipv4_mapped () { return IpAddr :: V4 (mapped) ; } IpAddr :: V6 (* self) } pub const fn octets (& self) -> [u8 ; 16] { self . inner . s6_addr } } impl fmt :: Display for Ipv6Addr { fn fmt (& self , f : & mut fmt :: Formatter < '_ >) -> fmt :: Result { if f . precision () . is_none () && f . width () . is_none () { let segments = self . segments () ; if self . is_unspecified () { f . write_str ("::") } else if self . is_loopback () { f . write_str ("::1") } else if let Some (ipv4) = self . to_ipv4 () { match segments [5] { 0 => write ! (f , "::{}" , ipv4) , 0xffff => write ! (f , "::ffff:{}" , ipv4) , _ => unreachable ! () , } } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } } else { const IPV6_BUF_LEN : usize = (4 * 8) + 7 ; let mut buf = [0u8 ; IPV6_BUF_LEN] ; let mut buf_slice = & mut buf [..] ; write ! (buf_slice , "{}" , self) . unwrap () ; let len = IPV6_BUF_LEN - buf_slice . len () ; let buf = unsafe { crate :: str :: from_utf8_unchecked (& buf [.. len]) } ; f . pad (buf) } } } impl fmt :: Debug for Ipv6Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl Clone for Ipv6Addr { fn clone (& self) -> Ipv6Addr { * self } } impl PartialEq for Ipv6Addr { fn eq (& self , other : & Ipv6Addr) -> bool { self . inner . s6_addr == other . inner . s6_addr } } impl PartialEq < IpAddr > for Ipv6Addr { fn eq (& self , other : & IpAddr) -> bool { match other { IpAddr :: V4 (_) => false , IpAddr :: V6 (v6) => self == v6 , } } } impl PartialEq < Ipv6Addr > for IpAddr { fn eq (& self , other : & Ipv6Addr) -> bool { match self { IpAddr :: V4 (_) => false , IpAddr :: V6 (v6) => v6 == other , } } } impl Eq for Ipv6Addr { } impl hash :: Hash for Ipv6Addr { fn hash < H : hash :: Hasher > (& self , s : & mut H) { self . inner . s6_addr . hash (s) } } impl PartialOrd for Ipv6Addr { fn partial_cmp (& self , other : & Ipv6Addr) -> Option < Ordering > { Some (self . cmp (other)) } } impl PartialOrd < Ipv6Addr > for IpAddr { fn partial_cmp (& self , other : & Ipv6Addr) -> Option < Ordering > { match self { IpAddr :: V4 (_) => Some (Ordering :: Less) , IpAddr :: V6 (v6) => v6 . partial_cmp (other) , } } } impl PartialOrd < IpAddr > for Ipv6Addr { fn partial_cmp (& self , other : & IpAddr) -> Option < Ordering > { match other { IpAddr :: V4 (_) => Some (Ordering :: Greater) , IpAddr :: V6 (v6) => self . partial_cmp (v6) , } } } impl Ord for Ipv6Addr { fn cmp (& self , other : & Ipv6Addr) -> Ordering { self . segments () . cmp (& other . segments ()) } } impl AsInner < c :: in6_addr > for Ipv6Addr { fn as_inner (& self) -> & c :: in6_addr { & self . inner } } impl FromInner < c :: in6_addr > for Ipv6Addr { fn from_inner (addr : c :: in6_addr) -> Ipv6Addr { Ipv6Addr { inner : addr } } } impl From < Ipv6Addr > for u128 { fn from (ip : Ipv6Addr) -> u128 { let ip = ip . octets () ; u128 :: from_be_bytes (ip) } } impl From < u128 > for Ipv6Addr { fn from (ip : u128) -> Ipv6Addr { Ipv6Addr :: from (ip . to_be_bytes ()) } } impl From < [u8 ; 16] > for Ipv6Addr { fn from (octets : [u8 ; 16]) -> Ipv6Addr { let inner = c :: in6_addr { s6_addr : octets } ; Ipv6Addr :: from_inner (inner) } } impl From < [u16 ; 8] > for Ipv6Addr { fn from (segments : [u16 ; 8]) -> Ipv6Addr { let [a , b , c , d , e , f , g , h] = segments ; Ipv6Addr :: new (a , b , c , d , e , f , g , h) } } impl From < [u8 ; 16] > for IpAddr { fn from (octets : [u8 ; 16]) -> IpAddr { IpAddr :: V6 (Ipv6Addr :: from (octets)) } } impl From < [u16 ; 8] > for IpAddr { fn from (segments : [u16 ; 8]) -> IpAddr { IpAddr :: V6 (Ipv6Addr :: from (segments)) } } diff --git a/vendor/prettyplease/examples/output.prettyplease.rs b/vendor/prettyplease/examples/output.prettyplease.rs new file mode 100644 index 00000000..45b65d00 --- /dev/null +++ b/vendor/prettyplease/examples/output.prettyplease.rs @@ -0,0 +1,593 @@ +use crate::cmp::Ordering; +use crate::fmt::{self, Write as FmtWrite}; +use crate::hash; +use crate::io::Write as IoWrite; +use crate::mem::transmute; +use crate::sys::net::netc as c; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { + V4(Ipv4Addr), + V6(Ipv6Addr), +} +#[derive(Copy)] +pub struct Ipv4Addr { + inner: c::in_addr, +} +#[derive(Copy)] +pub struct Ipv6Addr { + inner: c::in6_addr, +} +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global, +} +impl IpAddr { + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + pub const fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + pub const fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} +impl Ipv4Addr { + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + inner: c::in_addr { + s_addr: u32::from_ne_bytes([a, b, c, d]), + }, + } + } + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + #[doc(alias = "INADDR_ANY")] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + pub const fn octets(&self) -> [u8; 4] { + self.inner.s_addr.to_ne_bytes() + } + pub const fn is_unspecified(&self) -> bool { + self.inner.s_addr == 0 + } + pub const fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + pub const fn is_global(&self) -> bool { + if u32::from_be_bytes(self.octets()) == 0xc0000009 + || u32::from_be_bytes(self.octets()) == 0xc000000a + { + return true; + } + !self.is_private() && !self.is_loopback() && !self.is_link_local() + && !self.is_broadcast() && !self.is_documentation() && !self.is_shared() + && !(self.octets()[0] == 192 && self.octets()[1] == 0 + && self.octets()[2] == 0) && !self.is_reserved() + && !self.is_benchmarking() && self.octets()[0] != 0 + } + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) + } + pub const fn is_documentation(&self) -> bool { + matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _]) + } + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], + }, + } + } + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], + }, + } + } +} +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), + } + } +} +impl fmt::Debug for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl From for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} +impl From for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let octets = self.octets(); + if fmt.precision().is_none() && fmt.width().is_none() { + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } else { + const IPV4_BUF_LEN: usize = 15; + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + .unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } + } +} +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { + *self + } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} +impl Eq for Ipv4Addr {} +impl hash::Hash for Ipv4Addr { + fn hash(&self, s: &mut H) { + { self.inner.s_addr }.hash(s) + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) + } +} +impl IntoInner for Ipv4Addr { + fn into_inner(self) -> c::in_addr { + self.inner + } +} +impl From for u32 { + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + u32::from_be_bytes(ip) + } +} +impl From for Ipv4Addr { + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr::from(ip.to_be_bytes()) + } +} +impl From<[u8; 4]> for Ipv4Addr { + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) + } +} +impl From<[u8; 4]> for IpAddr { + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} +impl Ipv6Addr { + pub const fn new( + a: u16, + b: u16, + c: u16, + d: u16, + e: u16, + f: u16, + g: u16, + h: u16, + ) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; + Ipv6Addr { + inner: c::in6_addr { + s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, + }, + } + } + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + pub const fn segments(&self) -> [u16; 8] { + let [a, b, c, d, e, f, g, h] = unsafe { + transmute::<_, [u16; 8]>(self.inner.s6_addr) + }; + [ + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), + ] + } + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) + == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) + == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + pub const fn is_global(&self) -> bool { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + } + } + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) + && (self.segments()[2] == 0) + } + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() && !self.is_loopback() && !self.is_unicast_link_local() + && !self.is_unique_local() && !self.is_unspecified() + && !self.is_documentation() + } + pub const fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } + } + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + pub const fn to_ipv4_mapped(&self) -> Option { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + pub const fn to_ipv4(&self) -> Option { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { + None + } + } + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + pub const fn octets(&self) -> [u8; 16] { + self.inner.s6_addr + } +} +impl fmt::Display for Ipv6Addr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.precision().is_none() && f.width().is_none() { + let segments = self.segments(); + if self.is_unspecified() { + f.write_str("::") + } else if self.is_loopback() { + f.write_str("::1") + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + 0 => write!(f, "::{}", ipv4), + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { + #[derive(Copy, Clone, Default)] + struct Span { + start: usize, + len: usize, + } + let zeroes = { + let mut longest = Span::default(); + let mut current = Span::default(); + for (i, &segment) in segments.iter().enumerate() { + if segment == 0 { + if current.len == 0 { + current.start = i; + } + current.len += 1; + if current.len > longest.len { + longest = current; + } + } else { + current = Span::default(); + } + } + longest + }; + /// Write a colon-separated part of the address + #[inline] + fn fmt_subslice( + f: &mut fmt::Formatter<'_>, + chunk: &[u16], + ) -> fmt::Result { + if let Some((first, tail)) = chunk.split_first() { + write!(f, "{:x}", first)?; + for segment in tail { + f.write_char(':')?; + write!(f, "{:x}", segment)?; + } + } + Ok(()) + } + if zeroes.len > 1 { + fmt_subslice(f, &segments[..zeroes.start])?; + f.write_str("::")?; + fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) + } else { + fmt_subslice(f, &segments) + } + } + } else { + const IPV6_BUF_LEN: usize = (4 * 8) + 7; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!(buf_slice, "{}", self).unwrap(); + let len = IPV6_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) + } + } +} +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { + *self + } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} +impl Eq for Ipv6Addr {} +impl hash::Hash for Ipv6Addr { + fn hash(&self, s: &mut H) { + self.inner.s6_addr.hash(s) + } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} +impl AsInner for Ipv6Addr { + fn as_inner(&self) -> &c::in6_addr { + &self.inner + } +} +impl FromInner for Ipv6Addr { + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr { inner: addr } + } +} +impl From for u128 { + fn from(ip: Ipv6Addr) -> u128 { + let ip = ip.octets(); + u128::from_be_bytes(ip) + } +} +impl From for Ipv6Addr { + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} +impl From<[u8; 16]> for Ipv6Addr { + fn from(octets: [u8; 16]) -> Ipv6Addr { + let inner = c::in6_addr { s6_addr: octets }; + Ipv6Addr::from_inner(inner) + } +} +impl From<[u16; 8]> for Ipv6Addr { + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} +impl From<[u8; 16]> for IpAddr { + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} +impl From<[u16; 8]> for IpAddr { + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/vendor/prettyplease/examples/output.rustc.rs b/vendor/prettyplease/examples/output.rustc.rs new file mode 100644 index 00000000..a77a14a8 --- /dev/null +++ b/vendor/prettyplease/examples/output.rustc.rs @@ -0,0 +1,506 @@ +use crate::cmp::Ordering;use crate::fmt::{self, Write as FmtWrite}; +use crate::hash; +use crate::io::Write as IoWrite; +use crate::mem::transmute; +use crate::sys::net::netc as c; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), } +#[derive(Copy)] +pub struct Ipv4Addr { + inner: c::in_addr, +} +#[derive(Copy)] +pub struct Ipv6Addr { + inner: c::in6_addr, +} +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global, +} +impl IpAddr { + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + pub const fn is_ipv4(&self) -> bool { matches!(self, IpAddr :: V4(_)) } + pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr :: V6(_)) } + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} +impl Ipv4Addr { + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) }, + } + } + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + #[doc(alias = "INADDR_ANY")] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + pub const fn octets(&self) -> [u8; 4] { self.inner.s_addr.to_ne_bytes() } + pub const fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 } + pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 } + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + pub const fn is_global(&self) -> bool { + if u32::from_be_bytes(self.octets()) == 0xc0000009 || + u32::from_be_bytes(self.octets()) == 0xc000000a { + return true; + } + !self.is_private() && !self.is_loopback() && !self.is_link_local() && + !self.is_broadcast() && !self.is_documentation() && + !self.is_shared() && + !(self.octets()[0] == 192 && self.octets()[1] == 0 && + self.octets()[2] == 0) && !self.is_reserved() && + !self.is_benchmarking() && self.octets()[0] != 0 + } + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && + (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == + u32::from_be_bytes(Self::BROADCAST.octets()) + } + pub const fn is_documentation(&self) -> bool { + matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | + [203, 0, 113, _]) + } + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], + }, + } + } + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, + d], + }, + } + } +} +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), + } + } +} +impl fmt::Debug for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl From for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { IpAddr::V4(ipv4) } +} +impl From for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { IpAddr::V6(ipv6) } +} +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let octets = self.octets(); + if fmt.precision().is_none() && fmt.width().is_none() { + write!(fmt, "{}.{}.{}.{}", octets [0], octets [1], octets [2], + octets [3]) + } else { + const IPV4_BUF_LEN: usize = 15; + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!(buf_slice, "{}.{}.{}.{}", octets [0], octets [1], octets + [2], octets [3]).unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } + } +} +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { *self } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { IpAddr::V4(v4) => v4 == other, IpAddr::V6(_) => false, } + } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } + } +} +impl Eq for Ipv4Addr {} +impl hash::Hash for Ipv4Addr { + fn hash(&self, s: &mut H) { + { self.inner.s_addr }.hash(s) + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) + } +} +impl IntoInner for Ipv4Addr { + fn into_inner(self) -> c::in_addr { self.inner } +} +impl From for u32 { + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + u32::from_be_bytes(ip) + } +} +impl From for Ipv4Addr { + fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::from(ip.to_be_bytes()) } +} +impl From<[u8; 4]> for Ipv4Addr { + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) + } +} +impl From<[u8; 4]> for IpAddr { + fn from(octets: [u8; 4]) -> IpAddr { IpAddr::V4(Ipv4Addr::from(octets)) } +} +impl Ipv6Addr { + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, + h: u16) -> Ipv6Addr { + let addr16 = + [a.to_be(), b.to_be(), c.to_be(), d.to_be(), e.to_be(), f.to_be(), + g.to_be(), h.to_be()]; + Ipv6Addr { + inner: c::in6_addr { + s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, + }, + } + } + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + pub const fn segments(&self) -> [u16; 8] { + let [a, b, c, d, e, f, g, h] = + unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; + [u16::from_be(a), u16::from_be(b), u16::from_be(c), u16::from_be(d), + u16::from_be(e), u16::from_be(f), u16::from_be(g), + u16::from_be(h)] + } + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == + u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == + u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + pub const fn is_global(&self) -> bool { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + } + } + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + pub const fn is_unicast(&self) -> bool { !self.is_multicast() } + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && + (self.segments()[2] == 0) + } + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() && !self.is_loopback() && + !self.is_unicast_link_local() && !self.is_unique_local() && + !self.is_unspecified() && !self.is_documentation() + } + pub const fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { None } + } + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + pub const fn to_ipv4_mapped(&self) -> Option { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + pub const fn to_ipv4(&self) -> Option { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { None } + } + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + pub const fn octets(&self) -> [u8; 16] { self.inner.s6_addr } +} +impl fmt::Display for Ipv6Addr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.precision().is_none() && f.width().is_none() { + let segments = self.segments(); + if self.is_unspecified() { + f.write_str("::") + } else if self.is_loopback() { + f.write_str("::1") + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + 0 => write!(f, "::{}", ipv4), + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { + #[derive(Copy, Clone, Default)] + struct Span { + start: usize, + len: usize, + } + let zeroes = + { + let mut longest = Span::default(); + let mut current = Span::default(); + for (i, &segment) in segments.iter().enumerate() { + if segment == 0 { + if current.len == 0 { current.start = i; } + current.len += 1; + if current.len > longest.len { longest = current; } + } else { current = Span::default(); } + } + longest + }; + #[doc = " Write a colon-separated part of the address"] + #[inline] + fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) + -> fmt::Result { + if let Some((first, tail)) = chunk.split_first() { + write!(f, "{:x}", first)?; + for segment in tail { + f.write_char(':')?; + write!(f, "{:x}", segment)?; + } + } + Ok(()) + } + if zeroes.len > 1 { + fmt_subslice(f, &segments[..zeroes.start])?; + f.write_str("::")?; + fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) + } else { fmt_subslice(f, &segments) } + } + } else { + const IPV6_BUF_LEN: usize = (4 * 8) + 7; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!(buf_slice, "{}", self).unwrap(); + let len = IPV6_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) + } + } +} +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { *self } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { IpAddr::V4(_) => false, IpAddr::V6(v6) => self == v6, } + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { IpAddr::V4(_) => false, IpAddr::V6(v6) => v6 == other, } + } +} +impl Eq for Ipv6Addr {} +impl hash::Hash for Ipv6Addr { + fn hash(&self, s: &mut H) { self.inner.s6_addr.hash(s) } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} +impl AsInner for Ipv6Addr { + fn as_inner(&self) -> &c::in6_addr { &self.inner } +} +impl FromInner for Ipv6Addr { + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { Ipv6Addr { inner: addr } } +} +impl From for u128 { + fn from(ip: Ipv6Addr) -> u128 { + let ip = ip.octets(); + u128::from_be_bytes(ip) + } +} +impl From for Ipv6Addr { + fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::from(ip.to_be_bytes()) } +} +impl From<[u8; 16]> for Ipv6Addr { + fn from(octets: [u8; 16]) -> Ipv6Addr { + let inner = c::in6_addr { s6_addr: octets }; + Ipv6Addr::from_inner(inner) + } +} +impl From<[u16; 8]> for Ipv6Addr { + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} +impl From<[u8; 16]> for IpAddr { + fn from(octets: [u8; 16]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(octets)) } +} +impl From<[u16; 8]> for IpAddr { + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/vendor/prettyplease/examples/output.rustfmt.rs b/vendor/prettyplease/examples/output.rustfmt.rs new file mode 100644 index 00000000..3c7181d8 --- /dev/null +++ b/vendor/prettyplease/examples/output.rustfmt.rs @@ -0,0 +1,552 @@ +use crate::cmp::Ordering; +use crate::fmt::{self, Write as FmtWrite}; +use crate::hash; +use crate::io::Write as IoWrite; +use crate::mem::transmute; +use crate::sys::net::netc as c; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub enum IpAddr { + V4(Ipv4Addr), + V6(Ipv6Addr), +} +#[derive(Copy)] +pub struct Ipv4Addr { + inner: c::in_addr, +} +#[derive(Copy)] +pub struct Ipv6Addr { + inner: c::in6_addr, +} +#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[non_exhaustive] +pub enum Ipv6MulticastScope { + InterfaceLocal, + LinkLocal, + RealmLocal, + AdminLocal, + SiteLocal, + OrganizationLocal, + Global, +} +impl IpAddr { + pub const fn is_unspecified(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), + } + } + pub const fn is_loopback(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), + } + } + pub const fn is_global(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), + } + } + pub const fn is_multicast(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), + } + } + pub const fn is_documentation(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), + } + } + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + pub const fn is_ipv4(&self) -> bool { + matches!(self, IpAddr::V4(_)) + } + pub const fn is_ipv6(&self) -> bool { + matches!(self, IpAddr::V6(_)) + } + pub const fn to_canonical(&self) -> IpAddr { + match self { + &v4 @ IpAddr::V4(_) => v4, + IpAddr::V6(v6) => v6.to_canonical(), + } + } +} +impl Ipv4Addr { + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + Ipv4Addr { + inner: c::in_addr { + s_addr: u32::from_ne_bytes([a, b, c, d]), + }, + } + } + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); + #[doc(alias = "INADDR_ANY")] + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); + pub const fn octets(&self) -> [u8; 4] { + self.inner.s_addr.to_ne_bytes() + } + pub const fn is_unspecified(&self) -> bool { + self.inner.s_addr == 0 + } + pub const fn is_loopback(&self) -> bool { + self.octets()[0] == 127 + } + pub const fn is_private(&self) -> bool { + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, + } + } + pub const fn is_link_local(&self) -> bool { + matches!(self.octets(), [169, 254, ..]) + } + pub const fn is_global(&self) -> bool { + if u32::from_be_bytes(self.octets()) == 0xc0000009 + || u32::from_be_bytes(self.octets()) == 0xc000000a + { + return true; + } + !self.is_private() + && !self.is_loopback() + && !self.is_link_local() + && !self.is_broadcast() + && !self.is_documentation() + && !self.is_shared() + && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0) + && !self.is_reserved() + && !self.is_benchmarking() + && self.octets()[0] != 0 + } + pub const fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + pub const fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + pub const fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + pub const fn is_multicast(&self) -> bool { + self.octets()[0] >= 224 && self.octets()[0] <= 239 + } + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) + } + pub const fn is_documentation(&self) -> bool { + matches!( + self.octets(), + [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _] + ) + } + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d], + }, + } + } + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { + let [a, b, c, d] = self.octets(); + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d], + }, + } + } +} +impl fmt::Display for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), + } + } +} +impl fmt::Debug for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl From for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} +impl From for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} +impl fmt::Display for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let octets = self.octets(); + if fmt.precision().is_none() && fmt.width().is_none() { + write!( + fmt, + "{}.{}.{}.{}", + octets[0], octets[1], octets[2], octets[3] + ) + } else { + const IPV4_BUF_LEN: usize = 15; + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!( + buf_slice, + "{}.{}.{}.{}", + octets[0], octets[1], octets[2], octets[3] + ) + .unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } + } +} +impl fmt::Debug for Ipv4Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv4Addr { + fn clone(&self) -> Ipv4Addr { + *self + } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &Ipv4Addr) -> bool { + self.inner.s_addr == other.inner.s_addr + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv4Addr) -> bool { + match self { + IpAddr::V4(v4) => v4 == other, + IpAddr::V6(_) => false, + } + } +} +impl PartialEq for Ipv4Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(v4) => self == v4, + IpAddr::V6(_) => false, + } + } +} +impl Eq for Ipv4Addr {} +impl hash::Hash for Ipv4Addr { + fn hash(&self, s: &mut H) { + { self.inner.s_addr }.hash(s) + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv4Addr) -> Option { + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), + IpAddr::V6(_) => Some(Ordering::Greater), + } + } +} +impl PartialOrd for Ipv4Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), + IpAddr::V6(_) => Some(Ordering::Less), + } + } +} +impl Ord for Ipv4Addr { + fn cmp(&self, other: &Ipv4Addr) -> Ordering { + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) + } +} +impl IntoInner for Ipv4Addr { + fn into_inner(self) -> c::in_addr { + self.inner + } +} +impl From for u32 { + fn from(ip: Ipv4Addr) -> u32 { + let ip = ip.octets(); + u32::from_be_bytes(ip) + } +} +impl From for Ipv4Addr { + fn from(ip: u32) -> Ipv4Addr { + Ipv4Addr::from(ip.to_be_bytes()) + } +} +impl From<[u8; 4]> for Ipv4Addr { + fn from(octets: [u8; 4]) -> Ipv4Addr { + Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) + } +} +impl From<[u8; 4]> for IpAddr { + fn from(octets: [u8; 4]) -> IpAddr { + IpAddr::V4(Ipv4Addr::from(octets)) + } +} +impl Ipv6Addr { + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; + Ipv6Addr { + inner: c::in6_addr { + s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, + }, + } + } + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + pub const fn segments(&self) -> [u16; 8] { + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; + [ + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), + ] + } + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) + } + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) + } + pub const fn is_global(&self) -> bool { + match self.multicast_scope() { + Some(Ipv6MulticastScope::Global) => true, + None => self.is_unicast_global(), + _ => false, + } + } + pub const fn is_unique_local(&self) -> bool { + (self.segments()[0] & 0xfe00) == 0xfc00 + } + pub const fn is_unicast(&self) -> bool { + !self.is_multicast() + } + pub const fn is_unicast_link_local(&self) -> bool { + (self.segments()[0] & 0xffc0) == 0xfe80 + } + pub const fn is_documentation(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + } + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + pub const fn is_unicast_global(&self) -> bool { + self.is_unicast() + && !self.is_loopback() + && !self.is_unicast_link_local() + && !self.is_unique_local() + && !self.is_unspecified() + && !self.is_documentation() + } + pub const fn multicast_scope(&self) -> Option { + if self.is_multicast() { + match self.segments()[0] & 0x000f { + 1 => Some(Ipv6MulticastScope::InterfaceLocal), + 2 => Some(Ipv6MulticastScope::LinkLocal), + 3 => Some(Ipv6MulticastScope::RealmLocal), + 4 => Some(Ipv6MulticastScope::AdminLocal), + 5 => Some(Ipv6MulticastScope::SiteLocal), + 8 => Some(Ipv6MulticastScope::OrganizationLocal), + 14 => Some(Ipv6MulticastScope::Global), + _ => None, + } + } else { + None + } + } + pub const fn is_multicast(&self) -> bool { + (self.segments()[0] & 0xff00) == 0xff00 + } + pub const fn to_ipv4_mapped(&self) -> Option { + match self.octets() { + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { + Some(Ipv4Addr::new(a, b, c, d)) + } + _ => None, + } + } + pub const fn to_ipv4(&self) -> Option { + if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { + let [a, b] = ab.to_be_bytes(); + let [c, d] = cd.to_be_bytes(); + Some(Ipv4Addr::new(a, b, c, d)) + } else { + None + } + } + pub const fn to_canonical(&self) -> IpAddr { + if let Some(mapped) = self.to_ipv4_mapped() { + return IpAddr::V4(mapped); + } + IpAddr::V6(*self) + } + pub const fn octets(&self) -> [u8; 16] { + self.inner.s6_addr + } +} +impl fmt::Display for Ipv6Addr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.precision().is_none() && f.width().is_none() { + let segments = self.segments(); + if self.is_unspecified() { + f.write_str("::") + } else if self.is_loopback() { + f.write_str("::1") + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + 0 => write!(f, "::{}", ipv4), + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } + } else { + const IPV6_BUF_LEN: usize = (4 * 8) + 7; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + write!(buf_slice, "{}", self).unwrap(); + let len = IPV6_BUF_LEN - buf_slice.len(); + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) + } + } +} +impl fmt::Debug for Ipv6Addr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, fmt) + } +} +impl Clone for Ipv6Addr { + fn clone(&self) -> Ipv6Addr { + *self + } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &Ipv6Addr) -> bool { + self.inner.s6_addr == other.inner.s6_addr + } +} +impl PartialEq for Ipv6Addr { + fn eq(&self, other: &IpAddr) -> bool { + match other { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => self == v6, + } + } +} +impl PartialEq for IpAddr { + fn eq(&self, other: &Ipv6Addr) -> bool { + match self { + IpAddr::V4(_) => false, + IpAddr::V6(v6) => v6 == other, + } + } +} +impl Eq for Ipv6Addr {} +impl hash::Hash for Ipv6Addr { + fn hash(&self, s: &mut H) { + self.inner.s6_addr.hash(s) + } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + Some(self.cmp(other)) + } +} +impl PartialOrd for IpAddr { + fn partial_cmp(&self, other: &Ipv6Addr) -> Option { + match self { + IpAddr::V4(_) => Some(Ordering::Less), + IpAddr::V6(v6) => v6.partial_cmp(other), + } + } +} +impl PartialOrd for Ipv6Addr { + fn partial_cmp(&self, other: &IpAddr) -> Option { + match other { + IpAddr::V4(_) => Some(Ordering::Greater), + IpAddr::V6(v6) => self.partial_cmp(v6), + } + } +} +impl Ord for Ipv6Addr { + fn cmp(&self, other: &Ipv6Addr) -> Ordering { + self.segments().cmp(&other.segments()) + } +} +impl AsInner for Ipv6Addr { + fn as_inner(&self) -> &c::in6_addr { + &self.inner + } +} +impl FromInner for Ipv6Addr { + fn from_inner(addr: c::in6_addr) -> Ipv6Addr { + Ipv6Addr { inner: addr } + } +} +impl From for u128 { + fn from(ip: Ipv6Addr) -> u128 { + let ip = ip.octets(); + u128::from_be_bytes(ip) + } +} +impl From for Ipv6Addr { + fn from(ip: u128) -> Ipv6Addr { + Ipv6Addr::from(ip.to_be_bytes()) + } +} +impl From<[u8; 16]> for Ipv6Addr { + fn from(octets: [u8; 16]) -> Ipv6Addr { + let inner = c::in6_addr { s6_addr: octets }; + Ipv6Addr::from_inner(inner) + } +} +impl From<[u16; 8]> for Ipv6Addr { + fn from(segments: [u16; 8]) -> Ipv6Addr { + let [a, b, c, d, e, f, g, h] = segments; + Ipv6Addr::new(a, b, c, d, e, f, g, h) + } +} +impl From<[u8; 16]> for IpAddr { + fn from(octets: [u8; 16]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(octets)) + } +} +impl From<[u16; 8]> for IpAddr { + fn from(segments: [u16; 8]) -> IpAddr { + IpAddr::V6(Ipv6Addr::from(segments)) + } +} diff --git a/vendor/prettyplease/src/algorithm.rs b/vendor/prettyplease/src/algorithm.rs new file mode 100644 index 00000000..482b3ad7 --- /dev/null +++ b/vendor/prettyplease/src/algorithm.rs @@ -0,0 +1,386 @@ +// Adapted from https://github.com/rust-lang/rust/blob/1.57.0/compiler/rustc_ast_pretty/src/pp.rs. +// See "Algorithm notes" in the crate-level rustdoc. + +use crate::ring::RingBuffer; +use crate::{MARGIN, MIN_SPACE}; +use std::borrow::Cow; +use std::cmp; +use std::collections::VecDeque; +use std::iter; + +#[derive(Clone, Copy, PartialEq)] +pub enum Breaks { + Consistent, + Inconsistent, +} + +#[derive(Clone, Copy, Default)] +pub struct BreakToken { + pub offset: isize, + pub blank_space: usize, + pub pre_break: Option, + pub post_break: &'static str, + pub no_break: Option, + pub if_nonempty: bool, + pub never_break: bool, +} + +#[derive(Clone, Copy)] +pub struct BeginToken { + pub offset: isize, + pub breaks: Breaks, +} + +#[derive(Clone)] +pub enum Token { + String(Cow<'static, str>), + Break(BreakToken), + Begin(BeginToken), + End, +} + +#[derive(Copy, Clone)] +enum PrintFrame { + Fits(Breaks), + Broken(usize, Breaks), +} + +pub const SIZE_INFINITY: isize = 0xffff; + +pub struct Printer { + out: String, + // Number of spaces left on line + space: isize, + // Ring-buffer of tokens and calculated sizes + buf: RingBuffer, + // Total size of tokens already printed + left_total: isize, + // Total size of tokens enqueued, including printed and not yet printed + right_total: isize, + // Holds the ring-buffer index of the Begin that started the current block, + // possibly with the most recent Break after that Begin (if there is any) on + // top of it. Values are pushed and popped on the back of the queue using it + // like stack, and elsewhere old values are popped from the front of the + // queue as they become irrelevant due to the primary ring-buffer advancing. + scan_stack: VecDeque, + // Stack of blocks-in-progress being flushed by print + print_stack: Vec, + // Level of indentation of current line + indent: usize, + // Buffered indentation to avoid writing trailing whitespace + pending_indentation: usize, +} + +#[derive(Clone)] +struct BufEntry { + token: Token, + size: isize, +} + +impl Printer { + pub fn new() -> Self { + Printer { + out: String::new(), + space: MARGIN, + buf: RingBuffer::new(), + left_total: 0, + right_total: 0, + scan_stack: VecDeque::new(), + print_stack: Vec::new(), + indent: 0, + pending_indentation: 0, + } + } + + pub fn eof(mut self) -> String { + if !self.scan_stack.is_empty() { + self.check_stack(0); + self.advance_left(); + } + self.out + } + + pub fn scan_begin(&mut self, token: BeginToken) { + if self.scan_stack.is_empty() { + self.left_total = 1; + self.right_total = 1; + self.buf.clear(); + } + let right = self.buf.push(BufEntry { + token: Token::Begin(token), + size: -self.right_total, + }); + self.scan_stack.push_back(right); + } + + pub fn scan_end(&mut self) { + if self.scan_stack.is_empty() { + self.print_end(); + } else { + if !self.buf.is_empty() { + if let Token::Break(break_token) = self.buf.last().token { + if self.buf.len() >= 2 { + if let Token::Begin(_) = self.buf.second_last().token { + self.buf.pop_last(); + self.buf.pop_last(); + self.scan_stack.pop_back(); + self.scan_stack.pop_back(); + self.right_total -= break_token.blank_space as isize; + return; + } + } + if break_token.if_nonempty { + self.buf.pop_last(); + self.scan_stack.pop_back(); + self.right_total -= break_token.blank_space as isize; + } + } + } + let right = self.buf.push(BufEntry { + token: Token::End, + size: -1, + }); + self.scan_stack.push_back(right); + } + } + + pub fn scan_break(&mut self, token: BreakToken) { + if self.scan_stack.is_empty() { + self.left_total = 1; + self.right_total = 1; + self.buf.clear(); + } else { + self.check_stack(0); + } + let right = self.buf.push(BufEntry { + token: Token::Break(token), + size: -self.right_total, + }); + self.scan_stack.push_back(right); + self.right_total += token.blank_space as isize; + } + + pub fn scan_string(&mut self, string: Cow<'static, str>) { + if self.scan_stack.is_empty() { + self.print_string(string); + } else { + let len = string.len() as isize; + self.buf.push(BufEntry { + token: Token::String(string), + size: len, + }); + self.right_total += len; + self.check_stream(); + } + } + + #[track_caller] + pub fn offset(&mut self, offset: isize) { + match &mut self.buf.last_mut().token { + Token::Break(token) => token.offset += offset, + Token::Begin(_) => {} + Token::String(_) | Token::End => unreachable!(), + } + } + + pub fn end_with_max_width(&mut self, max: isize) { + let mut depth = 1; + for &index in self.scan_stack.iter().rev() { + let entry = &self.buf[index]; + match entry.token { + Token::Begin(_) => { + depth -= 1; + if depth == 0 { + if entry.size < 0 { + let actual_width = entry.size + self.right_total; + if actual_width > max { + self.buf.push(BufEntry { + token: Token::String(Cow::Borrowed("")), + size: SIZE_INFINITY, + }); + self.right_total += SIZE_INFINITY; + } + } + break; + } + } + Token::End => depth += 1, + Token::Break(_) => {} + Token::String(_) => unreachable!(), + } + } + self.scan_end(); + } + + pub fn ends_with(&self, ch: char) -> bool { + for i in self.buf.index_range().rev() { + if let Token::String(token) = &self.buf[i].token { + return token.ends_with(ch); + } + } + self.out.ends_with(ch) + } + + fn check_stream(&mut self) { + while self.right_total - self.left_total > self.space { + if *self.scan_stack.front().unwrap() == self.buf.index_range().start { + self.scan_stack.pop_front().unwrap(); + self.buf.first_mut().size = SIZE_INFINITY; + } + + self.advance_left(); + + if self.buf.is_empty() { + break; + } + } + } + + fn advance_left(&mut self) { + while self.buf.first().size >= 0 { + let left = self.buf.pop_first(); + + match left.token { + Token::String(string) => { + self.left_total += left.size; + self.print_string(string); + } + Token::Break(token) => { + self.left_total += token.blank_space as isize; + self.print_break(token, left.size); + } + Token::Begin(token) => self.print_begin(token, left.size), + Token::End => self.print_end(), + } + + if self.buf.is_empty() { + break; + } + } + } + + fn check_stack(&mut self, mut depth: usize) { + while let Some(&index) = self.scan_stack.back() { + let entry = &mut self.buf[index]; + match entry.token { + Token::Begin(_) => { + if depth == 0 { + break; + } + self.scan_stack.pop_back().unwrap(); + entry.size += self.right_total; + depth -= 1; + } + Token::End => { + self.scan_stack.pop_back().unwrap(); + entry.size = 1; + depth += 1; + } + Token::Break(_) => { + self.scan_stack.pop_back().unwrap(); + entry.size += self.right_total; + if depth == 0 { + break; + } + } + Token::String(_) => unreachable!(), + } + } + } + + fn get_top(&self) -> PrintFrame { + const OUTER: PrintFrame = PrintFrame::Broken(0, Breaks::Inconsistent); + self.print_stack.last().map_or(OUTER, PrintFrame::clone) + } + + fn print_begin(&mut self, token: BeginToken, size: isize) { + if cfg!(prettyplease_debug) { + self.out.push(match token.breaks { + Breaks::Consistent => '«', + Breaks::Inconsistent => '‹', + }); + if cfg!(prettyplease_debug_indent) { + self.out + .extend(token.offset.to_string().chars().map(|ch| match ch { + '0'..='9' => ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'] + [(ch as u8 - b'0') as usize], + '-' => '₋', + _ => unreachable!(), + })); + } + } + if size > self.space { + self.print_stack + .push(PrintFrame::Broken(self.indent, token.breaks)); + self.indent = usize::try_from(self.indent as isize + token.offset).unwrap(); + } else { + self.print_stack.push(PrintFrame::Fits(token.breaks)); + } + } + + fn print_end(&mut self) { + let breaks = match self.print_stack.pop().unwrap() { + PrintFrame::Broken(indent, breaks) => { + self.indent = indent; + breaks + } + PrintFrame::Fits(breaks) => breaks, + }; + if cfg!(prettyplease_debug) { + self.out.push(match breaks { + Breaks::Consistent => '»', + Breaks::Inconsistent => '›', + }); + } + } + + fn print_break(&mut self, token: BreakToken, size: isize) { + let fits = token.never_break + || match self.get_top() { + PrintFrame::Fits(..) => true, + PrintFrame::Broken(.., Breaks::Consistent) => false, + PrintFrame::Broken(.., Breaks::Inconsistent) => size <= self.space, + }; + if fits { + self.pending_indentation += token.blank_space; + self.space -= token.blank_space as isize; + if let Some(no_break) = token.no_break { + self.out.push(no_break); + self.space -= no_break.len_utf8() as isize; + } + if cfg!(prettyplease_debug) { + self.out.push('·'); + } + } else { + if let Some(pre_break) = token.pre_break { + self.print_indent(); + self.out.push(pre_break); + } + if cfg!(prettyplease_debug) { + self.out.push('·'); + } + self.out.push('\n'); + let indent = self.indent as isize + token.offset; + self.pending_indentation = usize::try_from(indent).unwrap(); + self.space = cmp::max(MARGIN - indent, MIN_SPACE); + if !token.post_break.is_empty() { + self.print_indent(); + self.out.push_str(token.post_break); + self.space -= token.post_break.len() as isize; + } + } + } + + fn print_string(&mut self, string: Cow<'static, str>) { + self.print_indent(); + self.out.push_str(&string); + self.space -= string.len() as isize; + } + + fn print_indent(&mut self) { + self.out.reserve(self.pending_indentation); + self.out + .extend(iter::repeat(' ').take(self.pending_indentation)); + self.pending_indentation = 0; + } +} diff --git a/vendor/prettyplease/src/attr.rs b/vendor/prettyplease/src/attr.rs new file mode 100644 index 00000000..b436283f --- /dev/null +++ b/vendor/prettyplease/src/attr.rs @@ -0,0 +1,288 @@ +use crate::algorithm::Printer; +use crate::fixup::FixupContext; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::{Delimiter, Group, TokenStream, TokenTree}; +use syn::{AttrStyle, Attribute, Expr, Lit, MacroDelimiter, Meta, MetaList, MetaNameValue}; + +impl Printer { + pub fn outer_attrs(&mut self, attrs: &[Attribute]) { + for attr in attrs { + if let AttrStyle::Outer = attr.style { + self.attr(attr); + } + } + } + + pub fn inner_attrs(&mut self, attrs: &[Attribute]) { + for attr in attrs { + if let AttrStyle::Inner(_) = attr.style { + self.attr(attr); + } + } + } + + fn attr(&mut self, attr: &Attribute) { + if let Some(mut doc) = value_of_attribute("doc", attr) { + if !doc.contains('\n') + && match attr.style { + AttrStyle::Outer => !doc.starts_with('/'), + AttrStyle::Inner(_) => true, + } + { + trim_trailing_spaces(&mut doc); + self.word(match attr.style { + AttrStyle::Outer => "///", + AttrStyle::Inner(_) => "//!", + }); + self.word(doc); + self.hardbreak(); + return; + } else if can_be_block_comment(&doc) + && match attr.style { + AttrStyle::Outer => !doc.starts_with(&['*', '/'][..]), + AttrStyle::Inner(_) => true, + } + { + trim_interior_trailing_spaces(&mut doc); + self.word(match attr.style { + AttrStyle::Outer => "/**", + AttrStyle::Inner(_) => "/*!", + }); + self.word(doc); + self.word("*/"); + self.hardbreak(); + return; + } + } else if let Some(mut comment) = value_of_attribute("comment", attr) { + if !comment.contains('\n') { + trim_trailing_spaces(&mut comment); + self.word("//"); + self.word(comment); + self.hardbreak(); + return; + } else if can_be_block_comment(&comment) && !comment.starts_with(&['*', '!'][..]) { + trim_interior_trailing_spaces(&mut comment); + self.word("/*"); + self.word(comment); + self.word("*/"); + self.hardbreak(); + return; + } + } + + self.word(match attr.style { + AttrStyle::Outer => "#", + AttrStyle::Inner(_) => "#!", + }); + self.word("["); + self.meta(&attr.meta); + self.word("]"); + self.space(); + } + + fn meta(&mut self, meta: &Meta) { + match meta { + Meta::Path(path) => self.path(path, PathKind::Simple), + Meta::List(meta) => self.meta_list(meta), + Meta::NameValue(meta) => self.meta_name_value(meta), + } + } + + fn meta_list(&mut self, meta: &MetaList) { + self.path(&meta.path, PathKind::Simple); + let delimiter = match meta.delimiter { + MacroDelimiter::Paren(_) => Delimiter::Parenthesis, + MacroDelimiter::Brace(_) => Delimiter::Brace, + MacroDelimiter::Bracket(_) => Delimiter::Bracket, + }; + let group = Group::new(delimiter, meta.tokens.clone()); + self.attr_tokens(TokenStream::from(TokenTree::Group(group))); + } + + fn meta_name_value(&mut self, meta: &MetaNameValue) { + self.path(&meta.path, PathKind::Simple); + self.word(" = "); + self.expr(&meta.value, FixupContext::NONE); + } + + fn attr_tokens(&mut self, tokens: TokenStream) { + let mut stack = Vec::new(); + stack.push((tokens.into_iter().peekable(), Delimiter::None)); + let mut space = Self::nbsp as fn(&mut Self); + + #[derive(PartialEq)] + enum State { + Word, + Punct, + TrailingComma, + } + + use State::*; + let mut state = Word; + + while let Some((tokens, delimiter)) = stack.last_mut() { + match tokens.next() { + Some(TokenTree::Ident(ident)) => { + if let Word = state { + space(self); + } + self.ident(&ident); + state = Word; + } + Some(TokenTree::Punct(punct)) => { + let ch = punct.as_char(); + if let (Word, '=') = (state, ch) { + self.nbsp(); + } + if ch == ',' && tokens.peek().is_none() { + self.trailing_comma(true); + state = TrailingComma; + } else { + self.token_punct(ch); + if ch == '=' { + self.nbsp(); + } else if ch == ',' { + space(self); + } + state = Punct; + } + } + Some(TokenTree::Literal(literal)) => { + if let Word = state { + space(self); + } + self.token_literal(&literal); + state = Word; + } + Some(TokenTree::Group(group)) => { + let delimiter = group.delimiter(); + let stream = group.stream(); + match delimiter { + Delimiter::Parenthesis => { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + state = Punct; + } + Delimiter::Brace => { + self.word("{"); + state = Punct; + } + Delimiter::Bracket => { + self.word("["); + state = Punct; + } + Delimiter::None => {} + } + stack.push((stream.into_iter().peekable(), delimiter)); + space = Self::space; + } + None => { + match delimiter { + Delimiter::Parenthesis => { + if state != TrailingComma { + self.zerobreak(); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + state = Punct; + } + Delimiter::Brace => { + self.word("}"); + state = Punct; + } + Delimiter::Bracket => { + self.word("]"); + state = Punct; + } + Delimiter::None => {} + } + stack.pop(); + if stack.is_empty() { + space = Self::nbsp; + } + } + } + } + } +} + +fn value_of_attribute(requested: &str, attr: &Attribute) -> Option { + let value = match &attr.meta { + Meta::NameValue(meta) if meta.path.is_ident(requested) => &meta.value, + _ => return None, + }; + let lit = match value { + Expr::Lit(expr) if expr.attrs.is_empty() => &expr.lit, + _ => return None, + }; + match lit { + Lit::Str(string) => Some(string.value()), + _ => None, + } +} + +pub fn has_outer(attrs: &[Attribute]) -> bool { + for attr in attrs { + if let AttrStyle::Outer = attr.style { + return true; + } + } + false +} + +pub fn has_inner(attrs: &[Attribute]) -> bool { + for attr in attrs { + if let AttrStyle::Inner(_) = attr.style { + return true; + } + } + false +} + +fn trim_trailing_spaces(doc: &mut String) { + doc.truncate(doc.trim_end_matches(' ').len()); +} + +fn trim_interior_trailing_spaces(doc: &mut String) { + if !doc.contains(" \n") { + return; + } + let mut trimmed = String::with_capacity(doc.len()); + let mut lines = doc.split('\n').peekable(); + while let Some(line) = lines.next() { + if lines.peek().is_some() { + trimmed.push_str(line.trim_end_matches(' ')); + trimmed.push('\n'); + } else { + trimmed.push_str(line); + } + } + *doc = trimmed; +} + +fn can_be_block_comment(value: &str) -> bool { + let mut depth = 0usize; + let bytes = value.as_bytes(); + let mut i = 0usize; + let upper = bytes.len() - 1; + + while i < upper { + if bytes[i] == b'/' && bytes[i + 1] == b'*' { + depth += 1; + i += 2; + } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { + if depth == 0 { + return false; + } + depth -= 1; + i += 2; + } else { + i += 1; + } + } + + depth == 0 && !value.ends_with('/') +} diff --git a/vendor/prettyplease/src/classify.rs b/vendor/prettyplease/src/classify.rs new file mode 100644 index 00000000..17648f6c --- /dev/null +++ b/vendor/prettyplease/src/classify.rs @@ -0,0 +1,324 @@ +use proc_macro2::{Delimiter, TokenStream, TokenTree}; +use std::ops::ControlFlow; +use syn::punctuated::Punctuated; +use syn::{Expr, MacroDelimiter, Path, PathArguments, ReturnType, Token, Type, TypeParamBound}; + +pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { + match expr { + Expr::Macro(expr) => !matches!(expr.mac.delimiter, MacroDelimiter::Brace(_)), + _ => requires_comma_to_be_match_arm(expr), + } +} + +pub(crate) fn requires_comma_to_be_match_arm(mut expr: &Expr) -> bool { + loop { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::If(_) + | Expr::Match(_) + | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc + | Expr::While(_) + | Expr::Loop(_) + | Expr::ForLoop(_) + | Expr::TryBlock(_) + | Expr::Const(_) => return false, + + Expr::Array(_) + | Expr::Assign(_) + | Expr::Async(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Break(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Closure(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Macro(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::Try(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Yield(_) + | Expr::Verbatim(_) => return true, + + Expr::Group(group) => expr = &group.expr, + + _ => return true, + } + } +} + +pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool { + loop { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Type::BareFn(t) => match &t.output { + ReturnType::Default => return false, + ReturnType::Type(_, ret) => ty = ret, + }, + Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Path(t) => match last_type_in_path(&t.path) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Ptr(t) => ty = &t.elem, + Type::Reference(t) => ty = &t.elem, + Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + + Type::Array(_) + | Type::Group(_) + | Type::Infer(_) + | Type::Macro(_) + | Type::Never(_) + | Type::Paren(_) + | Type::Slice(_) + | Type::Tuple(_) + | Type::Verbatim(_) => return false, + + _ => return false, + } + } + + fn last_type_in_path(path: &Path) -> ControlFlow { + match &path.segments.last().unwrap().arguments { + PathArguments::None => ControlFlow::Break(true), + PathArguments::AngleBracketed(_) => ControlFlow::Break(false), + PathArguments::Parenthesized(arg) => match &arg.output { + ReturnType::Default => ControlFlow::Break(false), + ReturnType::Type(_, ret) => ControlFlow::Continue(ret), + }, + } + } + + fn last_type_in_bounds( + bounds: &Punctuated, + ) -> ControlFlow { + match bounds.last().unwrap() { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(t) => last_type_in_path(&t.path), + TypeParamBound::Lifetime(_) + | TypeParamBound::PreciseCapture(_) + | TypeParamBound::Verbatim(_) => ControlFlow::Break(false), + _ => ControlFlow::Break(false), + } + } +} + +/// Whether the expression's first token is the label of a loop/block. +pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { + loop { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Block(e) => return e.label.is_some(), + Expr::ForLoop(e) => return e.label.is_some(), + Expr::Loop(e) => return e.label.is_some(), + Expr::While(e) => return e.label.is_some(), + + Expr::Assign(e) => expr = &e.left, + Expr::Await(e) => expr = &e.base, + Expr::Binary(e) => expr = &e.left, + Expr::Call(e) => expr = &e.func, + Expr::Cast(e) => expr = &e.expr, + Expr::Field(e) => expr = &e.base, + Expr::Index(e) => expr = &e.expr, + Expr::MethodCall(e) => expr = &e.receiver, + Expr::Range(e) => match &e.start { + Some(start) => expr = start, + None => return false, + }, + Expr::Try(e) => expr = &e.expr, + + Expr::Array(_) + | Expr::Async(_) + | Expr::Break(_) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::If(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::Yield(_) => return false, + + Expr::Group(e) => { + if !e.attrs.is_empty() { + return false; + } + expr = &e.expr; + } + + _ => return false, + } + } +} + +/// Whether the expression's last token is `}`. +pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { + loop { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Async(_) + | Expr::Block(_) + | Expr::Const(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Loop(_) + | Expr::Match(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Unsafe(_) + | Expr::While(_) => return true, + + Expr::Assign(e) => expr = &e.right, + Expr::Binary(e) => expr = &e.right, + Expr::Break(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + Expr::Cast(e) => return type_trailing_brace(&e.ty), + Expr::Closure(e) => expr = &e.body, + Expr::Group(e) => expr = &e.expr, + Expr::Let(e) => expr = &e.expr, + Expr::Macro(e) => return matches!(e.mac.delimiter, MacroDelimiter::Brace(_)), + Expr::Range(e) => match &e.end { + Some(end) => expr = end, + None => return false, + }, + Expr::RawAddr(e) => expr = &e.expr, + Expr::Reference(e) => expr = &e.expr, + Expr::Return(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + Expr::Unary(e) => expr = &e.expr, + Expr::Verbatim(e) => return tokens_trailing_brace(e), + Expr::Yield(e) => match &e.expr { + Some(e) => expr = e, + None => return false, + }, + + Expr::Array(_) + | Expr::Await(_) + | Expr::Call(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Lit(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Repeat(_) + | Expr::Try(_) + | Expr::Tuple(_) => return false, + + _ => return false, + } + } + + fn type_trailing_brace(mut ty: &Type) -> bool { + loop { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Type::BareFn(t) => match &t.output { + ReturnType::Default => return false, + ReturnType::Type(_, ret) => ty = ret, + }, + Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_brace) => return trailing_brace, + ControlFlow::Continue(t) => ty = t, + }, + Type::Macro(t) => return matches!(t.mac.delimiter, MacroDelimiter::Brace(_)), + Type::Path(t) => match last_type_in_path(&t.path) { + Some(t) => ty = t, + None => return false, + }, + Type::Ptr(t) => ty = &t.elem, + Type::Reference(t) => ty = &t.elem, + Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_brace) => return trailing_brace, + ControlFlow::Continue(t) => ty = t, + }, + Type::Verbatim(t) => return tokens_trailing_brace(t), + + Type::Array(_) + | Type::Group(_) + | Type::Infer(_) + | Type::Never(_) + | Type::Paren(_) + | Type::Slice(_) + | Type::Tuple(_) => return false, + + _ => return false, + } + } + } + + fn last_type_in_path(path: &Path) -> Option<&Type> { + match &path.segments.last().unwrap().arguments { + PathArguments::None | PathArguments::AngleBracketed(_) => None, + PathArguments::Parenthesized(arg) => match &arg.output { + ReturnType::Default => None, + ReturnType::Type(_, ret) => Some(ret), + }, + } + } + + fn last_type_in_bounds( + bounds: &Punctuated, + ) -> ControlFlow { + match bounds.last().unwrap() { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(t) => match last_type_in_path(&t.path) { + Some(t) => ControlFlow::Continue(t), + None => ControlFlow::Break(false), + }, + TypeParamBound::Lifetime(_) | TypeParamBound::PreciseCapture(_) => { + ControlFlow::Break(false) + } + TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)), + _ => ControlFlow::Break(false), + } + } + + fn tokens_trailing_brace(tokens: &TokenStream) -> bool { + if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() { + last.delimiter() == Delimiter::Brace + } else { + false + } + } +} diff --git a/vendor/prettyplease/src/convenience.rs b/vendor/prettyplease/src/convenience.rs new file mode 100644 index 00000000..bc4add6e --- /dev/null +++ b/vendor/prettyplease/src/convenience.rs @@ -0,0 +1,98 @@ +use crate::algorithm::{self, BeginToken, BreakToken, Breaks, Printer}; +use std::borrow::Cow; + +impl Printer { + pub fn ibox(&mut self, indent: isize) { + self.scan_begin(BeginToken { + offset: indent, + breaks: Breaks::Inconsistent, + }); + } + + pub fn cbox(&mut self, indent: isize) { + self.scan_begin(BeginToken { + offset: indent, + breaks: Breaks::Consistent, + }); + } + + pub fn end(&mut self) { + self.scan_end(); + } + + pub fn word>>(&mut self, wrd: S) { + let s = wrd.into(); + self.scan_string(s); + } + + fn spaces(&mut self, n: usize) { + self.scan_break(BreakToken { + blank_space: n, + ..BreakToken::default() + }); + } + + pub fn zerobreak(&mut self) { + self.spaces(0); + } + + pub fn space(&mut self) { + self.spaces(1); + } + + pub fn nbsp(&mut self) { + self.word(" "); + } + + pub fn hardbreak(&mut self) { + self.spaces(algorithm::SIZE_INFINITY as usize); + } + + pub fn space_if_nonempty(&mut self) { + self.scan_break(BreakToken { + blank_space: 1, + if_nonempty: true, + ..BreakToken::default() + }); + } + + pub fn hardbreak_if_nonempty(&mut self) { + self.scan_break(BreakToken { + blank_space: algorithm::SIZE_INFINITY as usize, + if_nonempty: true, + ..BreakToken::default() + }); + } + + pub fn trailing_comma(&mut self, is_last: bool) { + if is_last { + self.scan_break(BreakToken { + pre_break: Some(','), + ..BreakToken::default() + }); + } else { + self.word(","); + self.space(); + } + } + + pub fn trailing_comma_or_space(&mut self, is_last: bool) { + if is_last { + self.scan_break(BreakToken { + blank_space: 1, + pre_break: Some(','), + ..BreakToken::default() + }); + } else { + self.word(","); + self.space(); + } + } + + pub fn neverbreak(&mut self) { + self.scan_break(BreakToken { + never_break: true, + ..BreakToken::default() + }); + } +} diff --git a/vendor/prettyplease/src/data.rs b/vendor/prettyplease/src/data.rs new file mode 100644 index 00000000..3561a49b --- /dev/null +++ b/vendor/prettyplease/src/data.rs @@ -0,0 +1,79 @@ +use crate::algorithm::Printer; +use crate::fixup::FixupContext; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::INDENT; +use syn::{Field, Fields, FieldsUnnamed, Variant, VisRestricted, Visibility}; + +impl Printer { + pub fn variant(&mut self, variant: &Variant) { + self.outer_attrs(&variant.attrs); + self.ident(&variant.ident); + match &variant.fields { + Fields::Named(fields) => { + self.nbsp(); + self.word("{"); + self.cbox(INDENT); + self.space(); + for field in fields.named.iter().delimited() { + self.field(&field); + self.trailing_comma_or_space(field.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + Fields::Unnamed(fields) => { + self.cbox(INDENT); + self.fields_unnamed(fields); + self.end(); + } + Fields::Unit => {} + } + if let Some((_eq_token, discriminant)) = &variant.discriminant { + self.word(" = "); + self.expr(discriminant, FixupContext::NONE); + } + } + + pub fn fields_unnamed(&mut self, fields: &FieldsUnnamed) { + self.word("("); + self.zerobreak(); + for field in fields.unnamed.iter().delimited() { + self.field(&field); + self.trailing_comma(field.is_last); + } + self.offset(-INDENT); + self.word(")"); + } + + pub fn field(&mut self, field: &Field) { + self.outer_attrs(&field.attrs); + self.visibility(&field.vis); + if let Some(ident) = &field.ident { + self.ident(ident); + self.word(": "); + } + self.ty(&field.ty); + } + + pub fn visibility(&mut self, vis: &Visibility) { + match vis { + Visibility::Public(_) => self.word("pub "), + Visibility::Restricted(vis) => self.vis_restricted(vis), + Visibility::Inherited => {} + } + } + + fn vis_restricted(&mut self, vis: &VisRestricted) { + self.word("pub("); + let omit_in = vis.path.get_ident().map_or(false, |ident| { + matches!(ident.to_string().as_str(), "self" | "super" | "crate") + }); + if !omit_in { + self.word("in "); + } + self.path(&vis.path, PathKind::Simple); + self.word(") "); + } +} diff --git a/vendor/prettyplease/src/expr.rs b/vendor/prettyplease/src/expr.rs new file mode 100644 index 00000000..55b1b605 --- /dev/null +++ b/vendor/prettyplease/src/expr.rs @@ -0,0 +1,1533 @@ +use crate::algorithm::{BreakToken, Printer}; +use crate::attr; +use crate::classify; +use crate::fixup::FixupContext; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::precedence::Precedence; +use crate::stmt; +use crate::INDENT; +use proc_macro2::TokenStream; +use syn::punctuated::Punctuated; +use syn::{ + token, Arm, Attribute, BinOp, Block, Expr, ExprArray, ExprAssign, ExprAsync, ExprAwait, + ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprConst, ExprContinue, + ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLet, ExprLit, ExprLoop, + ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprRawAddr, + ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, + ExprUnsafe, ExprWhile, ExprYield, FieldValue, Index, Label, Lit, Member, PointerMutability, + RangeLimits, ReturnType, Stmt, Token, UnOp, +}; + +impl Printer { + pub fn expr(&mut self, expr: &Expr, mut fixup: FixupContext) { + let needs_paren = fixup.parenthesize(expr); + if needs_paren { + self.word("("); + fixup = FixupContext::NONE; + } + + let beginning_of_line = false; + + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Array(expr) => self.expr_array(expr), + Expr::Assign(expr) => self.expr_assign(expr, fixup), + Expr::Async(expr) => self.expr_async(expr), + Expr::Await(expr) => self.expr_await(expr, beginning_of_line, fixup), + Expr::Binary(expr) => self.expr_binary(expr, fixup), + Expr::Block(expr) => self.expr_block(expr), + Expr::Break(expr) => self.expr_break(expr, fixup), + Expr::Call(expr) => self.expr_call(expr, beginning_of_line, fixup), + Expr::Cast(expr) => self.expr_cast(expr, fixup), + Expr::Closure(expr) => self.expr_closure(expr, fixup), + Expr::Const(expr) => self.expr_const(expr), + Expr::Continue(expr) => self.expr_continue(expr), + Expr::Field(expr) => self.expr_field(expr, beginning_of_line, fixup), + Expr::ForLoop(expr) => self.expr_for_loop(expr), + Expr::Group(expr) => self.expr_group(expr, fixup), + Expr::If(expr) => self.expr_if(expr), + Expr::Index(expr) => self.expr_index(expr, beginning_of_line, fixup), + Expr::Infer(expr) => self.expr_infer(expr), + Expr::Let(expr) => self.expr_let(expr, fixup), + Expr::Lit(expr) => self.expr_lit(expr), + Expr::Loop(expr) => self.expr_loop(expr), + Expr::Macro(expr) => self.expr_macro(expr), + Expr::Match(expr) => self.expr_match(expr), + Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line, fixup), + Expr::Paren(expr) => self.expr_paren(expr), + Expr::Path(expr) => self.expr_path(expr), + Expr::Range(expr) => self.expr_range(expr, fixup), + Expr::RawAddr(expr) => self.expr_raw_addr(expr, fixup), + Expr::Reference(expr) => self.expr_reference(expr, fixup), + Expr::Repeat(expr) => self.expr_repeat(expr), + Expr::Return(expr) => self.expr_return(expr, fixup), + Expr::Struct(expr) => self.expr_struct(expr), + Expr::Try(expr) => self.expr_try(expr, beginning_of_line, fixup), + Expr::TryBlock(expr) => self.expr_try_block(expr), + Expr::Tuple(expr) => self.expr_tuple(expr), + Expr::Unary(expr) => self.expr_unary(expr, fixup), + Expr::Unsafe(expr) => self.expr_unsafe(expr), + Expr::Verbatim(expr) => self.expr_verbatim(expr, fixup), + Expr::While(expr) => self.expr_while(expr), + Expr::Yield(expr) => self.expr_yield(expr, fixup), + _ => unimplemented!("unknown Expr"), + } + + if needs_paren { + self.word(")"); + } + } + + pub fn expr_beginning_of_line( + &mut self, + expr: &Expr, + mut needs_paren: bool, + beginning_of_line: bool, + mut fixup: FixupContext, + ) { + needs_paren |= fixup.parenthesize(expr); + if needs_paren { + self.word("("); + fixup = FixupContext::NONE; + } + + match expr { + Expr::Await(expr) => self.expr_await(expr, beginning_of_line, fixup), + Expr::Field(expr) => self.expr_field(expr, beginning_of_line, fixup), + Expr::Index(expr) => self.expr_index(expr, beginning_of_line, fixup), + Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line, fixup), + Expr::Try(expr) => self.expr_try(expr, beginning_of_line, fixup), + _ => self.expr(expr, fixup), + } + + if needs_paren { + self.word(")"); + } + } + + fn prefix_subexpr( + &mut self, + expr: &Expr, + mut needs_paren: bool, + beginning_of_line: bool, + mut fixup: FixupContext, + ) { + needs_paren |= fixup.parenthesize(expr); + if needs_paren { + self.word("("); + fixup = FixupContext::NONE; + } + + match expr { + Expr::Await(expr) => self.prefix_subexpr_await(expr, beginning_of_line, fixup), + Expr::Call(expr) => self.prefix_subexpr_call(expr, fixup), + Expr::Field(expr) => self.prefix_subexpr_field(expr, beginning_of_line, fixup), + Expr::Index(expr) => self.prefix_subexpr_index(expr, beginning_of_line, fixup), + Expr::MethodCall(expr) => { + let unindent_call_args = false; + self.prefix_subexpr_method_call(expr, beginning_of_line, unindent_call_args, fixup); + } + Expr::Try(expr) => self.prefix_subexpr_try(expr, beginning_of_line, fixup), + _ => { + self.cbox(-INDENT); + self.expr(expr, fixup); + self.end(); + } + } + + if needs_paren { + self.word(")"); + } + } + + fn expr_condition(&mut self, expr: &Expr) { + self.cbox(0); + self.expr(expr, FixupContext::new_condition()); + if needs_newline_if_wrap(expr) { + self.space(); + } else { + self.nbsp(); + } + self.end(); + } + + pub fn subexpr(&mut self, expr: &Expr, needs_paren: bool, mut fixup: FixupContext) { + if needs_paren { + self.word("("); + fixup = FixupContext::NONE; + } + + self.expr(expr, fixup); + + if needs_paren { + self.word(")"); + } + } + + fn expr_array(&mut self, expr: &ExprArray) { + self.outer_attrs(&expr.attrs); + if expr.elems.is_empty() { + self.word("[]"); + } else if simple_array(&expr.elems) { + self.cbox(INDENT); + self.word("["); + self.zerobreak(); + self.ibox(0); + for elem in expr.elems.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + if !elem.is_last { + self.word(","); + self.space(); + } + } + self.end(); + self.trailing_comma(true); + self.offset(-INDENT); + self.word("]"); + self.end(); + } else { + self.word("["); + self.cbox(INDENT); + self.zerobreak(); + for elem in expr.elems.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + self.trailing_comma(elem.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("]"); + } + } + + fn expr_assign(&mut self, expr: &ExprAssign, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.left, + false, + false, + Precedence::Assign, + ); + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign); + + self.outer_attrs(&expr.attrs); + self.ibox(0); + if !expr.attrs.is_empty() { + self.word("("); + } + self.subexpr(&expr.left, left_prec <= Precedence::Range, left_fixup); + self.word(" = "); + self.neverbreak(); + self.expr(&expr.right, right_fixup); + if !expr.attrs.is_empty() { + self.word(")"); + } + self.end(); + } + + fn expr_async(&mut self, expr: &ExprAsync) { + self.outer_attrs(&expr.attrs); + self.word("async "); + if expr.capture.is_some() { + self.word("move "); + } + self.cbox(INDENT); + self.small_block(&expr.block, &expr.attrs); + self.end(); + } + + fn expr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.cbox(INDENT); + self.prefix_subexpr_await(expr, beginning_of_line, fixup); + self.end(); + } + + fn prefix_subexpr_await( + &mut self, + expr: &ExprAwait, + beginning_of_line: bool, + fixup: FixupContext, + ) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&expr.base); + + self.prefix_subexpr( + &expr.base, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + if !(beginning_of_line && is_short_ident(&expr.base)) { + self.scan_break(BreakToken { + no_break: self.ends_with('.').then_some(' '), + ..BreakToken::default() + }); + } + self.word(".await"); + } + + fn expr_binary(&mut self, expr: &ExprBinary, fixup: FixupContext) { + let binop_prec = Precedence::of_binop(&expr.op); + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.left, + match &expr.op { + BinOp::Sub(_) + | BinOp::Mul(_) + | BinOp::And(_) + | BinOp::Or(_) + | BinOp::BitAnd(_) + | BinOp::BitOr(_) + | BinOp::Shl(_) + | BinOp::Lt(_) => true, + _ => false, + }, + match &expr.op { + BinOp::Shl(_) | BinOp::Lt(_) => true, + _ => false, + }, + binop_prec, + ); + let left_needs_group = match binop_prec { + Precedence::Assign => left_prec <= Precedence::Range, + Precedence::Compare => left_prec <= binop_prec, + _ => left_prec < binop_prec, + }; + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec); + let right_needs_group = binop_prec != Precedence::Assign + && right_fixup.rightmost_subexpression_precedence(&expr.right) <= binop_prec; + + self.outer_attrs(&expr.attrs); + self.ibox(INDENT); + self.ibox(-INDENT); + if !expr.attrs.is_empty() { + self.word("("); + } + self.subexpr(&expr.left, left_needs_group, left_fixup); + self.end(); + self.space(); + self.binary_operator(&expr.op); + self.nbsp(); + self.subexpr(&expr.right, right_needs_group, right_fixup); + if !expr.attrs.is_empty() { + self.word(")"); + } + self.end(); + } + + pub fn expr_block(&mut self, expr: &ExprBlock) { + self.outer_attrs(&expr.attrs); + if let Some(label) = &expr.label { + self.label(label); + } + self.cbox(INDENT); + self.small_block(&expr.block, &expr.attrs); + self.end(); + } + + fn expr_break(&mut self, expr: &ExprBreak, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.word("break"); + if let Some(lifetime) = &expr.label { + self.nbsp(); + self.lifetime(lifetime); + } + if let Some(value) = &expr.expr { + self.nbsp(); + self.subexpr( + value, + expr.label.is_none() && classify::expr_leading_label(value), + fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump), + ); + } + } + + fn expr_call(&mut self, expr: &ExprCall, beginning_of_line: bool, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.func, + true, + false, + Precedence::Unambiguous, + ); + let needs_paren = if let Expr::Field(func) = &*expr.func { + matches!(func.member, Member::Named(_)) + } else { + left_prec < Precedence::Unambiguous + }; + + self.outer_attrs(&expr.attrs); + self.expr_beginning_of_line(&expr.func, needs_paren, beginning_of_line, left_fixup); + self.word("("); + self.call_args(&expr.args); + self.word(")"); + } + + fn prefix_subexpr_call(&mut self, expr: &ExprCall, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.func, + true, + false, + Precedence::Unambiguous, + ); + let needs_paren = if let Expr::Field(func) = &*expr.func { + matches!(func.member, Member::Named(_)) + } else { + left_prec < Precedence::Unambiguous + }; + + let beginning_of_line = false; + self.prefix_subexpr(&expr.func, needs_paren, beginning_of_line, left_fixup); + self.word("("); + self.call_args(&expr.args); + self.word(")"); + } + + fn expr_cast(&mut self, expr: &ExprCast, fixup: FixupContext) { + let (left_prec, left_fixup) = + fixup.leftmost_subexpression_with_operator(&expr.expr, false, false, Precedence::Cast); + + self.outer_attrs(&expr.attrs); + self.ibox(INDENT); + self.ibox(-INDENT); + if !expr.attrs.is_empty() { + self.word("("); + } + self.subexpr(&expr.expr, left_prec < Precedence::Cast, left_fixup); + self.end(); + self.space(); + self.word("as "); + self.ty(&expr.ty); + if !expr.attrs.is_empty() { + self.word(")"); + } + self.end(); + } + + fn expr_closure(&mut self, expr: &ExprClosure, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.ibox(0); + if let Some(bound_lifetimes) = &expr.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + if expr.constness.is_some() { + self.word("const "); + } + if expr.movability.is_some() { + self.word("static "); + } + if expr.asyncness.is_some() { + self.word("async "); + } + if expr.capture.is_some() { + self.word("move "); + } + self.cbox(INDENT); + self.word("|"); + for pat in expr.inputs.iter().delimited() { + if pat.is_first { + self.zerobreak(); + } + self.pat(&pat); + if !pat.is_last { + self.word(","); + self.space(); + } + } + match &expr.output { + ReturnType::Default => { + self.word("|"); + self.space(); + self.offset(-INDENT); + self.end(); + self.neverbreak(); + let wrap_in_brace = match &*expr.body { + Expr::Match(ExprMatch { attrs, .. }) | Expr::Call(ExprCall { attrs, .. }) => { + attr::has_outer(attrs) + } + body => !is_blocklike(body), + }; + if wrap_in_brace { + self.cbox(INDENT); + let okay_to_brace = parseable_as_stmt(&expr.body); + self.scan_break(BreakToken { + pre_break: Some(if okay_to_brace { '{' } else { '(' }), + ..BreakToken::default() + }); + self.expr( + &expr.body, + fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump), + ); + self.scan_break(BreakToken { + offset: -INDENT, + pre_break: (okay_to_brace && stmt::add_semi(&expr.body)).then_some(';'), + post_break: if okay_to_brace { "}" } else { ")" }, + ..BreakToken::default() + }); + self.end(); + } else { + self.expr( + &expr.body, + fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump), + ); + } + } + ReturnType::Type(_arrow, ty) => { + if !expr.inputs.is_empty() { + self.trailing_comma(true); + self.offset(-INDENT); + } + self.word("|"); + self.end(); + self.word(" -> "); + self.ty(ty); + self.nbsp(); + self.neverbreak(); + if matches!(&*expr.body, Expr::Block(body) if body.attrs.is_empty() && body.label.is_none()) + { + self.expr( + &expr.body, + fixup.rightmost_subexpression_fixup(false, false, Precedence::Jump), + ); + } else { + self.cbox(INDENT); + self.expr_as_small_block(&expr.body, 0); + self.end(); + } + } + } + self.end(); + } + + pub fn expr_const(&mut self, expr: &ExprConst) { + self.outer_attrs(&expr.attrs); + self.word("const "); + self.cbox(INDENT); + self.small_block(&expr.block, &expr.attrs); + self.end(); + } + + fn expr_continue(&mut self, expr: &ExprContinue) { + self.outer_attrs(&expr.attrs); + self.word("continue"); + if let Some(lifetime) = &expr.label { + self.nbsp(); + self.lifetime(lifetime); + } + } + + fn expr_field(&mut self, expr: &ExprField, beginning_of_line: bool, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.cbox(INDENT); + self.prefix_subexpr_field(expr, beginning_of_line, fixup); + self.end(); + } + + fn prefix_subexpr_field( + &mut self, + expr: &ExprField, + beginning_of_line: bool, + fixup: FixupContext, + ) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&expr.base); + + self.prefix_subexpr( + &expr.base, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + if !(beginning_of_line && is_short_ident(&expr.base)) { + self.scan_break(BreakToken { + no_break: self.ends_with('.').then_some(' '), + ..BreakToken::default() + }); + } + self.word("."); + self.member(&expr.member); + } + + fn expr_for_loop(&mut self, expr: &ExprForLoop) { + self.outer_attrs(&expr.attrs); + self.ibox(0); + if let Some(label) = &expr.label { + self.label(label); + } + self.word("for "); + self.pat(&expr.pat); + self.word(" in "); + self.neverbreak(); + self.expr_condition(&expr.expr); + self.word("{"); + self.neverbreak(); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + self.inner_attrs(&expr.attrs); + for stmt in expr.body.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.end(); + } + + fn expr_group(&mut self, expr: &ExprGroup, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.expr(&expr.expr, fixup); + } + + fn expr_if(&mut self, expr: &ExprIf) { + self.outer_attrs(&expr.attrs); + self.cbox(INDENT); + self.word("if "); + self.cbox(-INDENT); + self.expr_condition(&expr.cond); + self.end(); + if let Some((_else_token, else_branch)) = &expr.else_branch { + let mut else_branch = &**else_branch; + self.small_block(&expr.then_branch, &[]); + loop { + self.word(" else "); + match else_branch { + Expr::If(expr) => { + self.word("if "); + self.cbox(-INDENT); + self.expr_condition(&expr.cond); + self.end(); + self.small_block(&expr.then_branch, &[]); + if let Some((_else_token, next)) = &expr.else_branch { + else_branch = next; + continue; + } + } + Expr::Block(expr) => { + self.small_block(&expr.block, &[]); + } + // If not one of the valid expressions to exist in an else + // clause, wrap in a block. + other => self.expr_as_small_block(other, INDENT), + } + break; + } + } else if expr.then_branch.stmts.is_empty() { + self.word("{}"); + } else { + self.word("{"); + self.hardbreak(); + for stmt in expr.then_branch.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.word("}"); + } + self.end(); + } + + fn expr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.expr, + true, + false, + Precedence::Unambiguous, + ); + + self.outer_attrs(&expr.attrs); + self.expr_beginning_of_line( + &expr.expr, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + self.word("["); + self.expr(&expr.index, FixupContext::NONE); + self.word("]"); + } + + fn prefix_subexpr_index( + &mut self, + expr: &ExprIndex, + beginning_of_line: bool, + fixup: FixupContext, + ) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_operator( + &expr.expr, + true, + false, + Precedence::Unambiguous, + ); + + self.prefix_subexpr( + &expr.expr, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + self.word("["); + self.expr(&expr.index, FixupContext::NONE); + self.word("]"); + } + + fn expr_infer(&mut self, expr: &ExprInfer) { + self.outer_attrs(&expr.attrs); + self.word("_"); + } + + fn expr_let(&mut self, expr: &ExprLet, fixup: FixupContext) { + let (right_prec, right_fixup) = fixup.rightmost_subexpression(&expr.expr, Precedence::Let); + + self.outer_attrs(&expr.attrs); + self.ibox(0); + self.word("let "); + self.ibox(0); + self.pat(&expr.pat); + self.end(); + self.word(" = "); + self.neverbreak(); + self.ibox(0); + self.subexpr(&expr.expr, right_prec < Precedence::Let, right_fixup); + self.end(); + self.end(); + } + + pub fn expr_lit(&mut self, expr: &ExprLit) { + self.outer_attrs(&expr.attrs); + self.lit(&expr.lit); + } + + fn expr_loop(&mut self, expr: &ExprLoop) { + self.outer_attrs(&expr.attrs); + if let Some(label) = &expr.label { + self.label(label); + } + self.word("loop {"); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + self.inner_attrs(&expr.attrs); + for stmt in expr.body.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + + pub fn expr_macro(&mut self, expr: &ExprMacro) { + self.outer_attrs(&expr.attrs); + let semicolon = false; + self.mac(&expr.mac, None, semicolon); + } + + fn expr_match(&mut self, expr: &ExprMatch) { + self.outer_attrs(&expr.attrs); + self.ibox(0); + self.word("match "); + self.expr_condition(&expr.expr); + self.word("{"); + self.neverbreak(); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + self.inner_attrs(&expr.attrs); + for arm in &expr.arms { + self.arm(arm); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.end(); + } + + fn expr_method_call( + &mut self, + expr: &ExprMethodCall, + beginning_of_line: bool, + fixup: FixupContext, + ) { + self.outer_attrs(&expr.attrs); + self.cbox(INDENT); + let unindent_call_args = beginning_of_line && is_short_ident(&expr.receiver); + self.prefix_subexpr_method_call(expr, beginning_of_line, unindent_call_args, fixup); + self.end(); + } + + fn prefix_subexpr_method_call( + &mut self, + expr: &ExprMethodCall, + beginning_of_line: bool, + unindent_call_args: bool, + fixup: FixupContext, + ) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&expr.receiver); + + self.prefix_subexpr( + &expr.receiver, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + if !(beginning_of_line && is_short_ident(&expr.receiver)) { + self.scan_break(BreakToken { + no_break: self.ends_with('.').then_some(' '), + ..BreakToken::default() + }); + } + self.word("."); + self.ident(&expr.method); + if let Some(turbofish) = &expr.turbofish { + self.angle_bracketed_generic_arguments(turbofish, PathKind::Expr); + } + self.cbox(if unindent_call_args { -INDENT } else { 0 }); + self.word("("); + self.call_args(&expr.args); + self.word(")"); + self.end(); + } + + fn expr_paren(&mut self, expr: &ExprParen) { + self.outer_attrs(&expr.attrs); + self.word("("); + self.expr(&expr.expr, FixupContext::NONE); + self.word(")"); + } + + pub fn expr_path(&mut self, expr: &ExprPath) { + self.outer_attrs(&expr.attrs); + self.qpath(&expr.qself, &expr.path, PathKind::Expr); + } + + pub fn expr_range(&mut self, expr: &ExprRange, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + if !expr.attrs.is_empty() { + self.word("("); + } + if let Some(start) = &expr.start { + let (left_prec, left_fixup) = + fixup.leftmost_subexpression_with_operator(start, true, false, Precedence::Range); + self.subexpr(start, left_prec <= Precedence::Range, left_fixup); + } else if self.ends_with('.') { + self.nbsp(); + } + self.word(match expr.limits { + RangeLimits::HalfOpen(_) => "..", + RangeLimits::Closed(_) => "..=", + }); + if let Some(end) = &expr.end { + let right_fixup = fixup.rightmost_subexpression_fixup(false, true, Precedence::Range); + let right_prec = right_fixup.rightmost_subexpression_precedence(end); + self.subexpr(end, right_prec <= Precedence::Range, right_fixup); + } + if !expr.attrs.is_empty() { + self.word(")"); + } + } + + fn expr_raw_addr(&mut self, expr: &ExprRawAddr, fixup: FixupContext) { + let (right_prec, right_fixup) = + fixup.rightmost_subexpression(&expr.expr, Precedence::Prefix); + + self.outer_attrs(&expr.attrs); + self.word("&raw "); + self.pointer_mutability(&expr.mutability); + self.nbsp(); + self.subexpr(&expr.expr, right_prec < Precedence::Prefix, right_fixup); + } + + fn expr_reference(&mut self, expr: &ExprReference, fixup: FixupContext) { + let (right_prec, right_fixup) = + fixup.rightmost_subexpression(&expr.expr, Precedence::Prefix); + + self.outer_attrs(&expr.attrs); + self.word("&"); + if expr.mutability.is_some() { + self.word("mut "); + } + self.subexpr(&expr.expr, right_prec < Precedence::Prefix, right_fixup); + } + + fn expr_repeat(&mut self, expr: &ExprRepeat) { + self.outer_attrs(&expr.attrs); + self.word("["); + self.expr(&expr.expr, FixupContext::NONE); + self.word("; "); + self.expr(&expr.len, FixupContext::NONE); + self.word("]"); + } + + fn expr_return(&mut self, expr: &ExprReturn, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.word("return"); + if let Some(value) = &expr.expr { + self.nbsp(); + self.expr( + value, + fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump), + ); + } + } + + fn expr_struct(&mut self, expr: &ExprStruct) { + self.outer_attrs(&expr.attrs); + self.cbox(INDENT); + self.ibox(-INDENT); + self.qpath(&expr.qself, &expr.path, PathKind::Expr); + self.end(); + self.word(" {"); + self.space_if_nonempty(); + for field_value in expr.fields.iter().delimited() { + self.field_value(&field_value); + self.trailing_comma_or_space(field_value.is_last && expr.rest.is_none()); + } + if let Some(rest) = &expr.rest { + self.word(".."); + self.expr(rest, FixupContext::NONE); + self.space(); + } + self.offset(-INDENT); + self.end_with_max_width(34); + self.word("}"); + } + + fn expr_try(&mut self, expr: &ExprTry, beginning_of_line: bool, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&expr.expr); + + self.outer_attrs(&expr.attrs); + self.expr_beginning_of_line( + &expr.expr, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + self.word("?"); + } + + fn prefix_subexpr_try(&mut self, expr: &ExprTry, beginning_of_line: bool, fixup: FixupContext) { + let (left_prec, left_fixup) = fixup.leftmost_subexpression_with_dot(&expr.expr); + + self.prefix_subexpr( + &expr.expr, + left_prec < Precedence::Unambiguous, + beginning_of_line, + left_fixup, + ); + self.word("?"); + } + + fn expr_try_block(&mut self, expr: &ExprTryBlock) { + self.outer_attrs(&expr.attrs); + self.word("try "); + self.cbox(INDENT); + self.small_block(&expr.block, &expr.attrs); + self.end(); + } + + fn expr_tuple(&mut self, expr: &ExprTuple) { + self.outer_attrs(&expr.attrs); + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for elem in expr.elems.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + if expr.elems.len() == 1 { + self.word(","); + self.zerobreak(); + } else { + self.trailing_comma(elem.is_last); + } + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + + fn expr_unary(&mut self, expr: &ExprUnary, fixup: FixupContext) { + let (right_prec, right_fixup) = + fixup.rightmost_subexpression(&expr.expr, Precedence::Prefix); + + self.outer_attrs(&expr.attrs); + self.unary_operator(&expr.op); + self.subexpr(&expr.expr, right_prec < Precedence::Prefix, right_fixup); + } + + fn expr_unsafe(&mut self, expr: &ExprUnsafe) { + self.outer_attrs(&expr.attrs); + self.word("unsafe "); + self.cbox(INDENT); + self.small_block(&expr.block, &expr.attrs); + self.end(); + } + + #[cfg(not(feature = "verbatim"))] + fn expr_verbatim(&mut self, expr: &TokenStream, _fixup: FixupContext) { + if !expr.is_empty() { + unimplemented!("Expr::Verbatim `{}`", expr); + } + } + + #[cfg(feature = "verbatim")] + fn expr_verbatim(&mut self, tokens: &TokenStream, fixup: FixupContext) { + use syn::parse::discouraged::Speculative; + use syn::parse::{Parse, ParseStream, Result}; + use syn::{parenthesized, Ident}; + + enum ExprVerbatim { + Empty, + Ellipsis, + Become(Become), + Builtin(Builtin), + } + + struct Become { + attrs: Vec, + tail_call: Expr, + } + + struct Builtin { + attrs: Vec, + name: Ident, + args: TokenStream, + } + + mod kw { + syn::custom_keyword!(builtin); + syn::custom_keyword!(raw); + } + + impl Parse for ExprVerbatim { + fn parse(input: ParseStream) -> Result { + let ahead = input.fork(); + let attrs = ahead.call(Attribute::parse_outer)?; + let lookahead = ahead.lookahead1(); + if input.is_empty() { + Ok(ExprVerbatim::Empty) + } else if lookahead.peek(Token![become]) { + input.advance_to(&ahead); + input.parse::()?; + let tail_call: Expr = input.parse()?; + Ok(ExprVerbatim::Become(Become { attrs, tail_call })) + } else if lookahead.peek(kw::builtin) { + input.advance_to(&ahead); + input.parse::()?; + input.parse::()?; + let name: Ident = input.parse()?; + let args; + parenthesized!(args in input); + let args: TokenStream = args.parse()?; + Ok(ExprVerbatim::Builtin(Builtin { attrs, name, args })) + } else if lookahead.peek(Token![...]) { + input.parse::()?; + Ok(ExprVerbatim::Ellipsis) + } else { + Err(lookahead.error()) + } + } + } + + let expr: ExprVerbatim = match syn::parse2(tokens.clone()) { + Ok(expr) => expr, + Err(_) => unimplemented!("Expr::Verbatim `{}`", tokens), + }; + + match expr { + ExprVerbatim::Empty => {} + ExprVerbatim::Ellipsis => { + self.word("..."); + } + ExprVerbatim::Become(expr) => { + self.outer_attrs(&expr.attrs); + self.word("become"); + self.nbsp(); + self.expr( + &expr.tail_call, + fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump), + ); + } + ExprVerbatim::Builtin(expr) => { + self.outer_attrs(&expr.attrs); + self.word("builtin # "); + self.ident(&expr.name); + self.word("("); + if !expr.args.is_empty() { + self.cbox(INDENT); + self.zerobreak(); + self.ibox(0); + self.macro_rules_tokens(expr.args, false); + self.end(); + self.zerobreak(); + self.offset(-INDENT); + self.end(); + } + self.word(")"); + } + } + } + + fn expr_while(&mut self, expr: &ExprWhile) { + self.outer_attrs(&expr.attrs); + if let Some(label) = &expr.label { + self.label(label); + } + self.word("while "); + self.expr_condition(&expr.cond); + self.word("{"); + self.neverbreak(); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + self.inner_attrs(&expr.attrs); + for stmt in expr.body.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + + fn expr_yield(&mut self, expr: &ExprYield, fixup: FixupContext) { + self.outer_attrs(&expr.attrs); + self.word("yield"); + if let Some(value) = &expr.expr { + self.nbsp(); + self.expr( + value, + fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump), + ); + } + } + + fn label(&mut self, label: &Label) { + self.lifetime(&label.name); + self.word(": "); + } + + fn field_value(&mut self, field_value: &FieldValue) { + self.outer_attrs(&field_value.attrs); + self.member(&field_value.member); + if field_value.colon_token.is_some() { + self.word(": "); + self.ibox(0); + self.expr(&field_value.expr, FixupContext::NONE); + self.end(); + } + } + + fn arm(&mut self, arm: &Arm) { + self.outer_attrs(&arm.attrs); + self.ibox(0); + self.pat(&arm.pat); + if let Some((_if_token, guard)) = &arm.guard { + self.word(" if "); + self.expr(guard, FixupContext::NONE); + } + self.word(" => "); + let empty_block; + let mut body = &*arm.body; + while let Expr::Block(expr) = body { + if expr.attrs.is_empty() && expr.label.is_none() { + let mut stmts = expr.block.stmts.iter(); + if let (Some(Stmt::Expr(inner, None)), None) = (stmts.next(), stmts.next()) { + body = inner; + continue; + } + } + break; + } + if let Expr::Tuple(expr) = body { + if expr.elems.is_empty() && expr.attrs.is_empty() { + empty_block = Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace::default(), + stmts: Vec::new(), + }, + }); + body = &empty_block; + } + } + if let Expr::Block(body) = body { + if let Some(label) = &body.label { + self.label(label); + } + self.word("{"); + self.neverbreak(); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + self.inner_attrs(&body.attrs); + for stmt in body.block.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } else { + self.neverbreak(); + self.cbox(INDENT); + let okay_to_brace = parseable_as_stmt(body); + self.scan_break(BreakToken { + pre_break: Some(if okay_to_brace { '{' } else { '(' }), + ..BreakToken::default() + }); + self.expr_beginning_of_line(body, false, true, FixupContext::new_match_arm()); + self.scan_break(BreakToken { + offset: -INDENT, + pre_break: (okay_to_brace && stmt::add_semi(body)).then_some(';'), + post_break: if okay_to_brace { "}" } else { ")," }, + no_break: classify::requires_comma_to_be_match_arm(body).then_some(','), + ..BreakToken::default() + }); + self.end(); + } + self.end(); + } + + fn call_args(&mut self, args: &Punctuated) { + let mut iter = args.iter(); + match (iter.next(), iter.next()) { + (Some(expr), None) if is_blocklike(expr) => { + self.expr(expr, FixupContext::NONE); + } + _ => { + self.cbox(INDENT); + self.zerobreak(); + for arg in args.iter().delimited() { + self.expr(&arg, FixupContext::NONE); + self.trailing_comma(arg.is_last); + } + self.offset(-INDENT); + self.end(); + } + } + } + + pub fn small_block(&mut self, block: &Block, attrs: &[Attribute]) { + self.word("{"); + if attr::has_inner(attrs) || !block.stmts.is_empty() { + self.space(); + self.inner_attrs(attrs); + match block.stmts.as_slice() { + [Stmt::Expr(expr, None)] if stmt::break_after(expr) => { + self.ibox(0); + self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt()); + self.end(); + self.space(); + } + _ => { + for stmt in block.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + } + } + self.offset(-INDENT); + } + self.word("}"); + } + + pub fn expr_as_small_block(&mut self, expr: &Expr, indent: isize) { + self.word("{"); + self.space(); + self.ibox(indent); + self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt()); + self.end(); + self.space(); + self.offset(-INDENT); + self.word("}"); + } + + pub fn member(&mut self, member: &Member) { + match member { + Member::Named(ident) => self.ident(ident), + Member::Unnamed(index) => self.index(index), + } + } + + fn index(&mut self, member: &Index) { + self.word(member.index.to_string()); + } + + fn binary_operator(&mut self, op: &BinOp) { + self.word( + match op { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + BinOp::Add(_) => "+", + BinOp::Sub(_) => "-", + BinOp::Mul(_) => "*", + BinOp::Div(_) => "/", + BinOp::Rem(_) => "%", + BinOp::And(_) => "&&", + BinOp::Or(_) => "||", + BinOp::BitXor(_) => "^", + BinOp::BitAnd(_) => "&", + BinOp::BitOr(_) => "|", + BinOp::Shl(_) => "<<", + BinOp::Shr(_) => ">>", + BinOp::Eq(_) => "==", + BinOp::Lt(_) => "<", + BinOp::Le(_) => "<=", + BinOp::Ne(_) => "!=", + BinOp::Ge(_) => ">=", + BinOp::Gt(_) => ">", + BinOp::AddAssign(_) => "+=", + BinOp::SubAssign(_) => "-=", + BinOp::MulAssign(_) => "*=", + BinOp::DivAssign(_) => "/=", + BinOp::RemAssign(_) => "%=", + BinOp::BitXorAssign(_) => "^=", + BinOp::BitAndAssign(_) => "&=", + BinOp::BitOrAssign(_) => "|=", + BinOp::ShlAssign(_) => "<<=", + BinOp::ShrAssign(_) => ">>=", + _ => unimplemented!("unknown BinOp"), + }, + ); + } + + fn unary_operator(&mut self, op: &UnOp) { + self.word( + match op { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + UnOp::Deref(_) => "*", + UnOp::Not(_) => "!", + UnOp::Neg(_) => "-", + _ => unimplemented!("unknown UnOp"), + }, + ); + } + + fn pointer_mutability(&mut self, mutability: &PointerMutability) { + match mutability { + PointerMutability::Const(_) => self.word("const"), + PointerMutability::Mut(_) => self.word("mut"), + } + } +} + +fn needs_newline_if_wrap(expr: &Expr) -> bool { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Array(_) + | Expr::Async(_) + | Expr::Block(_) + | Expr::Break(ExprBreak { expr: None, .. }) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Infer(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::Path(_) + | Expr::Range(ExprRange { end: None, .. }) + | Expr::Repeat(_) + | Expr::Return(ExprReturn { expr: None, .. }) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::While(_) + | Expr::Yield(ExprYield { expr: None, .. }) => false, + + Expr::Assign(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Cast(_) + | Expr::Field(_) + | Expr::Index(_) + | Expr::MethodCall(_) => true, + + Expr::Break(ExprBreak { expr: Some(e), .. }) + | Expr::Call(ExprCall { func: e, .. }) + | Expr::Group(ExprGroup { expr: e, .. }) + | Expr::Let(ExprLet { expr: e, .. }) + | Expr::Paren(ExprParen { expr: e, .. }) + | Expr::Range(ExprRange { end: Some(e), .. }) + | Expr::RawAddr(ExprRawAddr { expr: e, .. }) + | Expr::Reference(ExprReference { expr: e, .. }) + | Expr::Return(ExprReturn { expr: Some(e), .. }) + | Expr::Try(ExprTry { expr: e, .. }) + | Expr::Unary(ExprUnary { expr: e, .. }) + | Expr::Yield(ExprYield { expr: Some(e), .. }) => needs_newline_if_wrap(e), + + _ => false, + } +} + +fn is_short_ident(expr: &Expr) -> bool { + if let Expr::Path(expr) = expr { + return expr.attrs.is_empty() + && expr.qself.is_none() + && expr + .path + .get_ident() + .map_or(false, |ident| ident.to_string().len() as isize <= INDENT); + } + false +} + +fn is_blocklike(expr: &Expr) -> bool { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Array(ExprArray { attrs, .. }) + | Expr::Async(ExprAsync { attrs, .. }) + | Expr::Block(ExprBlock { attrs, .. }) + | Expr::Closure(ExprClosure { attrs, .. }) + | Expr::Const(ExprConst { attrs, .. }) + | Expr::Struct(ExprStruct { attrs, .. }) + | Expr::TryBlock(ExprTryBlock { attrs, .. }) + | Expr::Tuple(ExprTuple { attrs, .. }) + | Expr::Unsafe(ExprUnsafe { attrs, .. }) => !attr::has_outer(attrs), + + Expr::Assign(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Break(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Try(_) + | Expr::Unary(_) + | Expr::Verbatim(_) + | Expr::While(_) + | Expr::Yield(_) => false, + + Expr::Group(e) => is_blocklike(&e.expr), + + _ => false, + } +} + +pub fn simple_block(expr: &Expr) -> Option<&ExprBlock> { + if let Expr::Block(expr) = expr { + if expr.attrs.is_empty() && expr.label.is_none() { + return Some(expr); + } + } + None +} + +pub fn simple_array(elements: &Punctuated) -> bool { + for expr in elements { + if let Expr::Lit(expr) = expr { + match expr.lit { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Lit::Byte(_) | Lit::Char(_) | Lit::Int(_) | Lit::Bool(_) => {} + + Lit::Str(_) | Lit::ByteStr(_) | Lit::CStr(_) | Lit::Float(_) | Lit::Verbatim(_) => { + return false; + } + + _ => return false, + } + } else { + return false; + } + } + true +} + +// Expressions for which `$expr` and `{ $expr }` mean the same thing. +// +// This is not the case for all expressions. For example `{} | x | x` has some +// bitwise OR operators while `{ {} |x| x }` has a block followed by a closure. +fn parseable_as_stmt(mut expr: &Expr) -> bool { + loop { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Array(_) + | Expr::Async(_) + | Expr::Block(_) + | Expr::Break(_) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Infer(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::While(_) + | Expr::Yield(_) => return true, + + Expr::Let(_) => return false, + + Expr::Assign(e) => { + if !classify::requires_semi_to_be_stmt(&e.left) { + return false; + } + expr = &e.left; + } + Expr::Await(e) => expr = &e.base, + Expr::Binary(e) => { + if !classify::requires_semi_to_be_stmt(&e.left) { + return false; + } + expr = &e.left; + } + Expr::Call(e) => { + if !classify::requires_semi_to_be_stmt(&e.func) { + return false; + } + expr = &e.func; + } + Expr::Cast(e) => { + if !classify::requires_semi_to_be_stmt(&e.expr) { + return false; + } + expr = &e.expr; + } + Expr::Field(e) => expr = &e.base, + Expr::Group(e) => expr = &e.expr, + Expr::Index(e) => { + if !classify::requires_semi_to_be_stmt(&e.expr) { + return false; + } + expr = &e.expr; + } + Expr::MethodCall(e) => expr = &e.receiver, + Expr::Range(e) => match &e.start { + None => return true, + Some(start) => { + if !classify::requires_semi_to_be_stmt(start) { + return false; + } + expr = start; + } + }, + Expr::Try(e) => expr = &e.expr, + + _ => return false, + } + } +} diff --git a/vendor/prettyplease/src/file.rs b/vendor/prettyplease/src/file.rs new file mode 100644 index 00000000..e23bd120 --- /dev/null +++ b/vendor/prettyplease/src/file.rs @@ -0,0 +1,17 @@ +use crate::algorithm::Printer; +use syn::File; + +impl Printer { + pub fn file(&mut self, file: &File) { + self.cbox(0); + if let Some(shebang) = &file.shebang { + self.word(shebang.clone()); + self.hardbreak(); + } + self.inner_attrs(&file.attrs); + for item in &file.items { + self.item(item); + } + self.end(); + } +} diff --git a/vendor/prettyplease/src/fixup.rs b/vendor/prettyplease/src/fixup.rs new file mode 100644 index 00000000..2355d490 --- /dev/null +++ b/vendor/prettyplease/src/fixup.rs @@ -0,0 +1,676 @@ +use crate::classify; +use crate::precedence::Precedence; +use syn::{ + Expr, ExprBreak, ExprRange, ExprRawAddr, ExprReference, ExprReturn, ExprUnary, ExprYield, +}; + +#[derive(Copy, Clone)] +pub struct FixupContext { + previous_operator: Precedence, + next_operator: Precedence, + + // Print expression such that it can be parsed back as a statement + // consisting of the original expression. + // + // The effect of this is for binary operators in statement position to set + // `leftmost_subexpression_in_stmt` when printing their left-hand operand. + // + // (match x {}) - 1; // match needs parens when LHS of binary operator + // + // match x {}; // not when its own statement + // + stmt: bool, + + // This is the difference between: + // + // (match x {}) - 1; // subexpression needs parens + // + // let _ = match x {} - 1; // no parens + // + // There are 3 distinguishable contexts in which `print_expr` might be + // called with the expression `$match` as its argument, where `$match` + // represents an expression of kind `ExprKind::Match`: + // + // - stmt=false leftmost_subexpression_in_stmt=false + // + // Example: `let _ = $match - 1;` + // + // No parentheses required. + // + // - stmt=false leftmost_subexpression_in_stmt=true + // + // Example: `$match - 1;` + // + // Must parenthesize `($match)`, otherwise parsing back the output as a + // statement would terminate the statement after the closing brace of + // the match, parsing `-1;` as a separate statement. + // + // - stmt=true leftmost_subexpression_in_stmt=false + // + // Example: `$match;` + // + // No parentheses required. + leftmost_subexpression_in_stmt: bool, + + // Print expression such that it can be parsed as a match arm. + // + // This is almost equivalent to `stmt`, but the grammar diverges a tiny bit + // between statements and match arms when it comes to braced macro calls. + // Macro calls with brace delimiter terminate a statement without a + // semicolon, but do not terminate a match-arm without comma. + // + // m! {} - 1; // two statements: a macro call followed by -1 literal + // + // match () { + // _ => m! {} - 1, // binary subtraction operator + // } + // + match_arm: bool, + + // This is almost equivalent to `leftmost_subexpression_in_stmt`, other than + // for braced macro calls. + // + // If we have `m! {} - 1` as an expression, the leftmost subexpression + // `m! {}` will need to be parenthesized in the statement case but not the + // match-arm case. + // + // (m! {}) - 1; // subexpression needs parens + // + // match () { + // _ => m! {} - 1, // no parens + // } + // + leftmost_subexpression_in_match_arm: bool, + + // This is the difference between: + // + // if let _ = (Struct {}) {} // needs parens + // + // match () { + // () if let _ = Struct {} => {} // no parens + // } + // + condition: bool, + + // This is the difference between: + // + // if break Struct {} == (break) {} // needs parens + // + // if break break == Struct {} {} // no parens + // + rightmost_subexpression_in_condition: bool, + + // This is the difference between: + // + // if break ({ x }).field + 1 {} needs parens + // + // if break 1 + { x }.field {} // no parens + // + leftmost_subexpression_in_optional_operand: bool, + + // This is the difference between: + // + // let _ = (return) - 1; // without paren, this would return -1 + // + // let _ = return + 1; // no paren because '+' cannot begin expr + // + next_operator_can_begin_expr: bool, + + // This is the difference between: + // + // let _ = 1 + return 1; // no parens if rightmost subexpression + // + // let _ = 1 + (return 1) + 1; // needs parens + // + next_operator_can_continue_expr: bool, + + // This is the difference between: + // + // let _ = x as u8 + T; + // + // let _ = (x as u8) < T; + // + // Without parens, the latter would want to parse `u8 Self { + FixupContext { + stmt: true, + ..FixupContext::NONE + } + } + + /// Create the initial fixup for printing an expression as the right-hand + /// side of a match arm. + pub fn new_match_arm() -> Self { + FixupContext { + match_arm: true, + ..FixupContext::NONE + } + } + + /// Create the initial fixup for printing an expression as the "condition" + /// of an `if` or `while`. There are a few other positions which are + /// grammatically equivalent and also use this, such as the iterator + /// expression in `for` and the scrutinee in `match`. + pub fn new_condition() -> Self { + FixupContext { + condition: true, + rightmost_subexpression_in_condition: true, + ..FixupContext::NONE + } + } + + /// Transform this fixup into the one that should apply when printing the + /// leftmost subexpression of the current expression. + /// + /// The leftmost subexpression is any subexpression that has the same first + /// token as the current expression, but has a different last token. + /// + /// For example in `$a + $b` and `$a.method()`, the subexpression `$a` is a + /// leftmost subexpression. + /// + /// Not every expression has a leftmost subexpression. For example neither + /// `-$a` nor `[$a]` have one. + pub fn leftmost_subexpression_with_operator( + self, + expr: &Expr, + next_operator_can_begin_expr: bool, + next_operator_can_begin_generics: bool, + precedence: Precedence, + ) -> (Precedence, Self) { + let fixup = FixupContext { + next_operator: precedence, + stmt: false, + leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt, + match_arm: false, + leftmost_subexpression_in_match_arm: self.match_arm + || self.leftmost_subexpression_in_match_arm, + rightmost_subexpression_in_condition: false, + next_operator_can_begin_expr, + next_operator_can_continue_expr: true, + next_operator_can_begin_generics, + ..self + }; + + (fixup.leftmost_subexpression_precedence(expr), fixup) + } + + /// Transform this fixup into the one that should apply when printing a + /// leftmost subexpression followed by a `.` or `?` token, which confer + /// different statement boundary rules compared to other leftmost + /// subexpressions. + pub fn leftmost_subexpression_with_dot(self, expr: &Expr) -> (Precedence, Self) { + let fixup = FixupContext { + next_operator: Precedence::Unambiguous, + stmt: self.stmt || self.leftmost_subexpression_in_stmt, + leftmost_subexpression_in_stmt: false, + match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + leftmost_subexpression_in_match_arm: false, + rightmost_subexpression_in_condition: false, + next_operator_can_begin_expr: false, + next_operator_can_continue_expr: true, + next_operator_can_begin_generics: false, + ..self + }; + + (fixup.leftmost_subexpression_precedence(expr), fixup) + } + + fn leftmost_subexpression_precedence(self, expr: &Expr) -> Precedence { + if !self.next_operator_can_begin_expr || self.next_operator == Precedence::Range { + if let Scan::Bailout = scan_right(expr, self, Precedence::MIN, 0, 0) { + if scan_left(expr, self) { + return Precedence::Unambiguous; + } + } + } + + self.precedence(expr) + } + + /// Transform this fixup into the one that should apply when printing the + /// rightmost subexpression of the current expression. + /// + /// The rightmost subexpression is any subexpression that has a different + /// first token than the current expression, but has the same last token. + /// + /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a + /// rightmost subexpression. + /// + /// Not every expression has a rightmost subexpression. For example neither + /// `[$b]` nor `$a.f($b)` have one. + pub fn rightmost_subexpression( + self, + expr: &Expr, + precedence: Precedence, + ) -> (Precedence, Self) { + let fixup = self.rightmost_subexpression_fixup(false, false, precedence); + (fixup.rightmost_subexpression_precedence(expr), fixup) + } + + pub fn rightmost_subexpression_fixup( + self, + reset_allow_struct: bool, + optional_operand: bool, + precedence: Precedence, + ) -> Self { + FixupContext { + previous_operator: precedence, + stmt: false, + leftmost_subexpression_in_stmt: false, + match_arm: false, + leftmost_subexpression_in_match_arm: false, + condition: self.condition && !reset_allow_struct, + leftmost_subexpression_in_optional_operand: self.condition && optional_operand, + ..self + } + } + + pub fn rightmost_subexpression_precedence(self, expr: &Expr) -> Precedence { + let default_prec = self.precedence(expr); + + if match self.previous_operator { + Precedence::Assign | Precedence::Let | Precedence::Prefix => { + default_prec < self.previous_operator + } + _ => default_prec <= self.previous_operator, + } && match self.next_operator { + Precedence::Range | Precedence::Or | Precedence::And => true, + _ => !self.next_operator_can_begin_expr, + } { + if let Scan::Bailout | Scan::Fail = scan_right(expr, self, self.previous_operator, 1, 0) + { + if scan_left(expr, self) { + return Precedence::Prefix; + } + } + } + + default_prec + } + + /// Determine whether parentheses are needed around the given expression to + /// head off the early termination of a statement or condition. + pub fn parenthesize(self, expr: &Expr) -> bool { + (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr)) + || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_))) + || (self.leftmost_subexpression_in_match_arm + && !classify::requires_comma_to_be_match_arm(expr)) + || (self.condition && matches!(expr, Expr::Struct(_))) + || (self.rightmost_subexpression_in_condition + && matches!( + expr, + Expr::Return(ExprReturn { expr: None, .. }) + | Expr::Yield(ExprYield { expr: None, .. }) + )) + || (self.rightmost_subexpression_in_condition + && !self.condition + && matches!( + expr, + Expr::Break(ExprBreak { expr: None, .. }) + | Expr::Path(_) + | Expr::Range(ExprRange { end: None, .. }) + )) + || (self.leftmost_subexpression_in_optional_operand + && matches!(expr, Expr::Block(expr) if expr.attrs.is_empty() && expr.label.is_none())) + } + + /// Determines the effective precedence of a subexpression. Some expressions + /// have higher or lower precedence when adjacent to particular operators. + fn precedence(self, expr: &Expr) -> Precedence { + if self.next_operator_can_begin_expr { + // Decrease precedence of value-less jumps when followed by an + // operator that would otherwise get interpreted as beginning a + // value for the jump. + if let Expr::Break(ExprBreak { expr: None, .. }) + | Expr::Return(ExprReturn { expr: None, .. }) + | Expr::Yield(ExprYield { expr: None, .. }) = expr + { + return Precedence::Jump; + } + } + + if !self.next_operator_can_continue_expr { + match expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. + Expr::Break(_) + | Expr::Closure(_) + | Expr::Let(_) + | Expr::Return(_) + | Expr::Yield(_) => { + return Precedence::Prefix; + } + Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, + _ => {} + } + } + + if self.next_operator_can_begin_generics { + if let Expr::Cast(cast) = expr { + if classify::trailing_unparameterized_path(&cast.ty) { + return Precedence::MIN; + } + } + } + + Precedence::of(expr) + } +} + +#[derive(Copy, Clone, PartialEq)] +enum Scan { + Fail, + Bailout, + Consume, +} + +fn scan_left(expr: &Expr, fixup: FixupContext) -> bool { + match expr { + Expr::Assign(_) => fixup.previous_operator <= Precedence::Assign, + Expr::Binary(e) => match Precedence::of_binop(&e.op) { + Precedence::Assign => fixup.previous_operator <= Precedence::Assign, + binop_prec => fixup.previous_operator < binop_prec, + }, + Expr::Cast(_) => fixup.previous_operator < Precedence::Cast, + Expr::Range(e) => e.start.is_none() || fixup.previous_operator < Precedence::Assign, + _ => true, + } +} + +fn scan_right( + expr: &Expr, + fixup: FixupContext, + precedence: Precedence, + fail_offset: u8, + bailout_offset: u8, +) -> Scan { + let consume_by_precedence = if match precedence { + Precedence::Assign | Precedence::Compare => precedence <= fixup.next_operator, + _ => precedence < fixup.next_operator, + } || fixup.next_operator == Precedence::MIN + { + Scan::Consume + } else { + Scan::Bailout + }; + if fixup.parenthesize(expr) { + return consume_by_precedence; + } + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Assign(e) if e.attrs.is_empty() => { + if match fixup.next_operator { + Precedence::Unambiguous => fail_offset >= 2, + _ => bailout_offset >= 1, + } { + return Scan::Consume; + } + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Assign); + let scan = scan_right( + &e.right, + right_fixup, + Precedence::Assign, + match fixup.next_operator { + Precedence::Unambiguous => fail_offset, + _ => 1, + }, + 1, + ); + if let Scan::Bailout | Scan::Consume = scan { + Scan::Consume + } else if let Precedence::Unambiguous = fixup.next_operator { + Scan::Fail + } else { + Scan::Bailout + } + } + Expr::Binary(e) if e.attrs.is_empty() => { + if match fixup.next_operator { + Precedence::Unambiguous => { + fail_offset >= 2 + && (consume_by_precedence == Scan::Consume || bailout_offset >= 1) + } + _ => bailout_offset >= 1, + } { + return Scan::Consume; + } + let binop_prec = Precedence::of_binop(&e.op); + if binop_prec == Precedence::Compare && fixup.next_operator == Precedence::Compare { + return Scan::Consume; + } + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, binop_prec); + let scan = scan_right( + &e.right, + right_fixup, + binop_prec, + match fixup.next_operator { + Precedence::Unambiguous => fail_offset, + _ => 1, + }, + consume_by_precedence as u8 - Scan::Bailout as u8, + ); + match scan { + Scan::Fail => {} + Scan::Bailout => return consume_by_precedence, + Scan::Consume => return Scan::Consume, + } + let right_needs_group = binop_prec != Precedence::Assign + && right_fixup.rightmost_subexpression_precedence(&e.right) <= binop_prec; + if right_needs_group { + consume_by_precedence + } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) { + Scan::Fail + } else { + Scan::Bailout + } + } + Expr::RawAddr(ExprRawAddr { expr, .. }) + | Expr::Reference(ExprReference { expr, .. }) + | Expr::Unary(ExprUnary { expr, .. }) => { + if match fixup.next_operator { + Precedence::Unambiguous => { + fail_offset >= 2 + && (consume_by_precedence == Scan::Consume || bailout_offset >= 1) + } + _ => bailout_offset >= 1, + } { + return Scan::Consume; + } + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Prefix); + let scan = scan_right( + expr, + right_fixup, + precedence, + match fixup.next_operator { + Precedence::Unambiguous => fail_offset, + _ => 1, + }, + consume_by_precedence as u8 - Scan::Bailout as u8, + ); + match scan { + Scan::Fail => {} + Scan::Bailout => return consume_by_precedence, + Scan::Consume => return Scan::Consume, + } + if right_fixup.rightmost_subexpression_precedence(expr) < Precedence::Prefix { + consume_by_precedence + } else if let (Scan::Fail, Precedence::Unambiguous) = (scan, fixup.next_operator) { + Scan::Fail + } else { + Scan::Bailout + } + } + Expr::Range(e) if e.attrs.is_empty() => match &e.end { + Some(end) => { + if fail_offset >= 2 { + return Scan::Consume; + } + let right_fixup = + fixup.rightmost_subexpression_fixup(false, true, Precedence::Range); + let scan = scan_right( + end, + right_fixup, + Precedence::Range, + fail_offset, + match fixup.next_operator { + Precedence::Assign | Precedence::Range => 0, + _ => 1, + }, + ); + if match (scan, fixup.next_operator) { + (Scan::Fail, _) => false, + (Scan::Bailout, Precedence::Assign | Precedence::Range) => false, + (Scan::Bailout | Scan::Consume, _) => true, + } { + return Scan::Consume; + } + if right_fixup.rightmost_subexpression_precedence(end) <= Precedence::Range { + Scan::Consume + } else { + Scan::Fail + } + } + None => { + if fixup.next_operator_can_begin_expr { + Scan::Consume + } else { + Scan::Fail + } + } + }, + Expr::Break(e) => match &e.expr { + Some(value) => { + if bailout_offset >= 1 || e.label.is_none() && classify::expr_leading_label(value) { + return Scan::Consume; + } + let right_fixup = fixup.rightmost_subexpression_fixup(true, true, Precedence::Jump); + match scan_right(value, right_fixup, Precedence::Jump, 1, 1) { + Scan::Fail => Scan::Bailout, + Scan::Bailout | Scan::Consume => Scan::Consume, + } + } + None => match fixup.next_operator { + Precedence::Assign if precedence > Precedence::Assign => Scan::Fail, + _ => Scan::Consume, + }, + }, + Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr { + Some(e) => { + if bailout_offset >= 1 { + return Scan::Consume; + } + let right_fixup = + fixup.rightmost_subexpression_fixup(true, false, Precedence::Jump); + match scan_right(e, right_fixup, Precedence::Jump, 1, 1) { + Scan::Fail => Scan::Bailout, + Scan::Bailout | Scan::Consume => Scan::Consume, + } + } + None => match fixup.next_operator { + Precedence::Assign if precedence > Precedence::Assign => Scan::Fail, + _ => Scan::Consume, + }, + }, + Expr::Closure(_) => Scan::Consume, + Expr::Let(e) => { + if bailout_offset >= 1 { + return Scan::Consume; + } + let right_fixup = fixup.rightmost_subexpression_fixup(false, false, Precedence::Let); + let scan = scan_right( + &e.expr, + right_fixup, + Precedence::Let, + 1, + if fixup.next_operator < Precedence::Let { + 0 + } else { + 1 + }, + ); + match scan { + Scan::Fail | Scan::Bailout if fixup.next_operator < Precedence::Let => { + return Scan::Bailout; + } + Scan::Consume => return Scan::Consume, + _ => {} + } + if right_fixup.rightmost_subexpression_precedence(&e.expr) < Precedence::Let { + Scan::Consume + } else if let Scan::Fail = scan { + Scan::Bailout + } else { + Scan::Consume + } + } + Expr::Group(e) => scan_right(&e.expr, fixup, precedence, fail_offset, bailout_offset), + Expr::Array(_) + | Expr::Assign(_) + | Expr::Async(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Block(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::Field(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::Repeat(_) + | Expr::Struct(_) + | Expr::Try(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::While(_) => match fixup.next_operator { + Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail, + _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => { + Scan::Fail + } + _ => consume_by_precedence, + }, + + _ => match fixup.next_operator { + Precedence::Assign | Precedence::Range if precedence == Precedence::Range => Scan::Fail, + _ if precedence == Precedence::Let && fixup.next_operator < Precedence::Let => { + Scan::Fail + } + _ => consume_by_precedence, + }, + } +} diff --git a/vendor/prettyplease/src/generics.rs b/vendor/prettyplease/src/generics.rs new file mode 100644 index 00000000..3f225b88 --- /dev/null +++ b/vendor/prettyplease/src/generics.rs @@ -0,0 +1,383 @@ +use crate::algorithm::Printer; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::TokenStream; +use std::ptr; +use syn::{ + BoundLifetimes, CapturedParam, ConstParam, Expr, GenericParam, Generics, LifetimeParam, + PreciseCapture, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, + TypeParamBound, WhereClause, WherePredicate, +}; + +impl Printer { + pub fn generics(&mut self, generics: &Generics) { + if generics.params.is_empty() { + return; + } + + self.word("<"); + self.cbox(0); + self.zerobreak(); + + // Print lifetimes before types and consts, regardless of their + // order in self.params. + #[derive(Ord, PartialOrd, Eq, PartialEq)] + enum Group { + First, + Second, + } + fn group(param: &GenericParam) -> Group { + match param { + GenericParam::Lifetime(_) => Group::First, + GenericParam::Type(_) | GenericParam::Const(_) => Group::Second, + } + } + let last = generics.params.iter().max_by_key(|param| group(param)); + for current_group in [Group::First, Group::Second] { + for param in &generics.params { + if group(param) == current_group { + self.generic_param(param); + self.trailing_comma(ptr::eq(param, last.unwrap())); + } + } + } + + self.offset(-INDENT); + self.end(); + self.word(">"); + } + + fn generic_param(&mut self, generic_param: &GenericParam) { + match generic_param { + GenericParam::Type(type_param) => self.type_param(type_param), + GenericParam::Lifetime(lifetime_param) => self.lifetime_param(lifetime_param), + GenericParam::Const(const_param) => self.const_param(const_param), + } + } + + pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) { + self.word("for<"); + for param in bound_lifetimes.lifetimes.iter().delimited() { + self.generic_param(¶m); + if !param.is_last { + self.word(", "); + } + } + self.word("> "); + } + + fn lifetime_param(&mut self, lifetime_param: &LifetimeParam) { + self.outer_attrs(&lifetime_param.attrs); + self.lifetime(&lifetime_param.lifetime); + for lifetime in lifetime_param.bounds.iter().delimited() { + if lifetime.is_first { + self.word(": "); + } else { + self.word(" + "); + } + self.lifetime(&lifetime); + } + } + + fn type_param(&mut self, type_param: &TypeParam) { + self.outer_attrs(&type_param.attrs); + self.ident(&type_param.ident); + self.ibox(INDENT); + for type_param_bound in type_param.bounds.iter().delimited() { + if type_param_bound.is_first { + self.word(": "); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&type_param_bound); + } + if let Some(default) = &type_param.default { + self.space(); + self.word("= "); + self.ty(default); + } + self.end(); + } + + pub fn type_param_bound(&mut self, type_param_bound: &TypeParamBound) { + match type_param_bound { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TypeParamBound::Trait(trait_bound) => { + let tilde_const = false; + self.trait_bound(trait_bound, tilde_const); + } + TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime), + TypeParamBound::PreciseCapture(precise_capture) => { + self.precise_capture(precise_capture); + } + TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound), + _ => unimplemented!("unknown TypeParamBound"), + } + } + + fn trait_bound(&mut self, trait_bound: &TraitBound, tilde_const: bool) { + if trait_bound.paren_token.is_some() { + self.word("("); + } + if tilde_const { + self.word("~const "); + } + self.trait_bound_modifier(&trait_bound.modifier); + if let Some(bound_lifetimes) = &trait_bound.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + for segment in trait_bound.path.segments.iter().delimited() { + if !segment.is_first || trait_bound.path.leading_colon.is_some() { + self.word("::"); + } + self.path_segment(&segment, PathKind::Type); + } + if trait_bound.paren_token.is_some() { + self.word(")"); + } + } + + fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) { + match trait_bound_modifier { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(_question_mark) => self.word("?"), + } + } + + #[cfg(not(feature = "verbatim"))] + fn type_param_bound_verbatim(&mut self, bound: &TokenStream) { + unimplemented!("TypeParamBound::Verbatim `{}`", bound); + } + + #[cfg(feature = "verbatim")] + fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{parenthesized, token, Token}; + + enum TypeParamBoundVerbatim { + Ellipsis, + TildeConst(TraitBound), + } + + impl Parse for TypeParamBoundVerbatim { + fn parse(input: ParseStream) -> Result { + let content; + let (paren_token, content) = if input.peek(token::Paren) { + (Some(parenthesized!(content in input)), &content) + } else { + (None, input) + }; + let lookahead = content.lookahead1(); + if lookahead.peek(Token![~]) { + content.parse::()?; + content.parse::()?; + let mut bound: TraitBound = content.parse()?; + bound.paren_token = paren_token; + Ok(TypeParamBoundVerbatim::TildeConst(bound)) + } else if lookahead.peek(Token![...]) { + content.parse::()?; + Ok(TypeParamBoundVerbatim::Ellipsis) + } else { + Err(lookahead.error()) + } + } + } + + let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) { + Ok(bound) => bound, + Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens), + }; + + match bound { + TypeParamBoundVerbatim::Ellipsis => { + self.word("..."); + } + TypeParamBoundVerbatim::TildeConst(trait_bound) => { + let tilde_const = true; + self.trait_bound(&trait_bound, tilde_const); + } + } + } + + fn const_param(&mut self, const_param: &ConstParam) { + self.outer_attrs(&const_param.attrs); + self.word("const "); + self.ident(&const_param.ident); + self.word(": "); + self.ty(&const_param.ty); + if let Some(default) = &const_param.default { + self.word(" = "); + self.const_argument(default); + } + } + + pub fn where_clause_for_body(&mut self, where_clause: &Option) { + let hardbreaks = true; + let semi = false; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_semi(&mut self, where_clause: &Option) { + let hardbreaks = true; + let semi = true; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_oneline(&mut self, where_clause: &Option) { + let hardbreaks = false; + let semi = false; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + pub fn where_clause_oneline_semi(&mut self, where_clause: &Option) { + let hardbreaks = false; + let semi = true; + self.where_clause_impl(where_clause, hardbreaks, semi); + } + + fn where_clause_impl( + &mut self, + where_clause: &Option, + hardbreaks: bool, + semi: bool, + ) { + let where_clause = match where_clause { + Some(where_clause) if !where_clause.predicates.is_empty() => where_clause, + _ => { + if semi { + self.word(";"); + } else { + self.nbsp(); + } + return; + } + }; + if hardbreaks { + self.hardbreak(); + self.offset(-INDENT); + self.word("where"); + self.hardbreak(); + for predicate in where_clause.predicates.iter().delimited() { + self.where_predicate(&predicate); + if predicate.is_last && semi { + self.word(";"); + } else { + self.word(","); + self.hardbreak(); + } + } + if !semi { + self.offset(-INDENT); + } + } else { + self.space(); + self.offset(-INDENT); + self.word("where"); + self.space(); + for predicate in where_clause.predicates.iter().delimited() { + self.where_predicate(&predicate); + if predicate.is_last && semi { + self.word(";"); + } else { + self.trailing_comma_or_space(predicate.is_last); + } + } + if !semi { + self.offset(-INDENT); + } + } + } + + fn where_predicate(&mut self, predicate: &WherePredicate) { + match predicate { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + WherePredicate::Type(predicate) => self.predicate_type(predicate), + WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate), + _ => unimplemented!("unknown WherePredicate"), + } + } + + fn predicate_type(&mut self, predicate: &PredicateType) { + if let Some(bound_lifetimes) = &predicate.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + self.ty(&predicate.bounded_ty); + self.word(":"); + if predicate.bounds.len() == 1 { + self.ibox(0); + } else { + self.ibox(INDENT); + } + for type_param_bound in predicate.bounds.iter().delimited() { + if type_param_bound.is_first { + self.nbsp(); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&type_param_bound); + } + self.end(); + } + + fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) { + self.lifetime(&predicate.lifetime); + self.word(":"); + self.ibox(INDENT); + for lifetime in predicate.bounds.iter().delimited() { + if lifetime.is_first { + self.nbsp(); + } else { + self.space(); + self.word("+ "); + } + self.lifetime(&lifetime); + } + self.end(); + } + + fn precise_capture(&mut self, precise_capture: &PreciseCapture) { + self.word("use<"); + for capture in precise_capture.params.iter().delimited() { + self.captured_param(&capture); + if !capture.is_last { + self.word(", "); + } + } + self.word(">"); + } + + fn captured_param(&mut self, capture: &CapturedParam) { + match capture { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + CapturedParam::Lifetime(lifetime) => self.lifetime(lifetime), + CapturedParam::Ident(ident) => self.ident(ident), + _ => unimplemented!("unknown CapturedParam"), + } + } + + pub fn const_argument(&mut self, expr: &Expr) { + match expr { + #![cfg_attr(all(test, exhaustive), allow(non_exhaustive_omitted_patterns))] + Expr::Lit(expr) => self.expr_lit(expr), + + Expr::Path(expr) + if expr.attrs.is_empty() + && expr.qself.is_none() + && expr.path.get_ident().is_some() => + { + self.expr_path(expr); + } + + Expr::Block(expr) => self.expr_block(expr), + + _ => { + self.cbox(INDENT); + self.expr_as_small_block(expr, 0); + self.end(); + } + } + } +} diff --git a/vendor/prettyplease/src/item.rs b/vendor/prettyplease/src/item.rs new file mode 100644 index 00000000..4e9d95d7 --- /dev/null +++ b/vendor/prettyplease/src/item.rs @@ -0,0 +1,1812 @@ +use crate::algorithm::Printer; +use crate::fixup::FixupContext; +use crate::iter::IterDelimited; +use crate::mac; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::TokenStream; +use syn::{ + Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic, + ForeignItemType, ImplItem, ImplItemConst, ImplItemFn, ImplItemMacro, ImplItemType, Item, + ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, + ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Receiver, + Signature, StaticMutability, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, + TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree, Variadic, +}; + +impl Printer { + pub fn item(&mut self, item: &Item) { + match item { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Item::Const(item) => self.item_const(item), + Item::Enum(item) => self.item_enum(item), + Item::ExternCrate(item) => self.item_extern_crate(item), + Item::Fn(item) => self.item_fn(item), + Item::ForeignMod(item) => self.item_foreign_mod(item), + Item::Impl(item) => self.item_impl(item), + Item::Macro(item) => self.item_macro(item), + Item::Mod(item) => self.item_mod(item), + Item::Static(item) => self.item_static(item), + Item::Struct(item) => self.item_struct(item), + Item::Trait(item) => self.item_trait(item), + Item::TraitAlias(item) => self.item_trait_alias(item), + Item::Type(item) => self.item_type(item), + Item::Union(item) => self.item_union(item), + Item::Use(item) => self.item_use(item), + Item::Verbatim(item) => self.item_verbatim(item), + _ => unimplemented!("unknown Item"), + } + } + + fn item_const(&mut self, item: &ItemConst) { + self.outer_attrs(&item.attrs); + self.cbox(0); + self.visibility(&item.vis); + self.word("const "); + self.ident(&item.ident); + self.generics(&item.generics); + self.word(": "); + self.ty(&item.ty); + self.word(" = "); + self.neverbreak(); + self.expr(&item.expr, FixupContext::NONE); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn item_enum(&mut self, item: &ItemEnum) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.word("enum "); + self.ident(&item.ident); + self.generics(&item.generics); + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + for variant in &item.variants { + self.variant(variant); + self.word(","); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_extern_crate(&mut self, item: &ItemExternCrate) { + self.outer_attrs(&item.attrs); + self.visibility(&item.vis); + self.word("extern crate "); + self.ident(&item.ident); + if let Some((_as_token, rename)) = &item.rename { + self.word(" as "); + self.ident(rename); + } + self.word(";"); + self.hardbreak(); + } + + fn item_fn(&mut self, item: &ItemFn) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.signature( + &item.sig, + #[cfg(feature = "verbatim")] + &verbatim::Safety::Disallowed, + ); + self.where_clause_for_body(&item.sig.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for stmt in item.block.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_foreign_mod(&mut self, item: &ItemForeignMod) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + if item.unsafety.is_some() { + self.word("unsafe "); + } + self.abi(&item.abi); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for foreign_item in &item.items { + self.foreign_item(foreign_item); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_impl(&mut self, item: &ItemImpl) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.ibox(-INDENT); + self.cbox(INDENT); + if item.defaultness.is_some() { + self.word("default "); + } + if item.unsafety.is_some() { + self.word("unsafe "); + } + self.word("impl"); + self.generics(&item.generics); + self.end(); + self.nbsp(); + if let Some((negative_polarity, path, _for_token)) = &item.trait_ { + if negative_polarity.is_some() { + self.word("!"); + } + self.path(path, PathKind::Type); + self.space(); + self.word("for "); + } + self.ty(&item.self_ty); + self.end(); + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for impl_item in &item.items { + self.impl_item(impl_item); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_macro(&mut self, item: &ItemMacro) { + self.outer_attrs(&item.attrs); + let semicolon = mac::requires_semi(&item.mac.delimiter); + self.mac(&item.mac, item.ident.as_ref(), semicolon); + self.hardbreak(); + } + + fn item_mod(&mut self, item: &ItemMod) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.unsafety.is_some() { + self.word("unsafe "); + } + self.word("mod "); + self.ident(&item.ident); + if let Some((_brace, items)) = &item.content { + self.word(" {"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for item in items { + self.item(item); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } else { + self.word(";"); + self.end(); + } + self.hardbreak(); + } + + fn item_static(&mut self, item: &ItemStatic) { + self.outer_attrs(&item.attrs); + self.cbox(0); + self.visibility(&item.vis); + self.word("static "); + self.static_mutability(&item.mutability); + self.ident(&item.ident); + self.word(": "); + self.ty(&item.ty); + self.word(" = "); + self.neverbreak(); + self.expr(&item.expr, FixupContext::NONE); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn item_struct(&mut self, item: &ItemStruct) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.word("struct "); + self.ident(&item.ident); + self.generics(&item.generics); + match &item.fields { + Fields::Named(fields) => { + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + for field in &fields.named { + self.field(field); + self.word(","); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + Fields::Unnamed(fields) => { + self.fields_unnamed(fields); + self.where_clause_semi(&item.generics.where_clause); + self.end(); + } + Fields::Unit => { + self.where_clause_semi(&item.generics.where_clause); + self.end(); + } + } + self.hardbreak(); + } + + fn item_trait(&mut self, item: &ItemTrait) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.unsafety.is_some() { + self.word("unsafe "); + } + if item.auto_token.is_some() { + self.word("auto "); + } + self.word("trait "); + self.ident(&item.ident); + self.generics(&item.generics); + for supertrait in item.supertraits.iter().delimited() { + if supertrait.is_first { + self.word(": "); + } else { + self.word(" + "); + } + self.type_param_bound(&supertrait); + } + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for trait_item in &item.items { + self.trait_item(trait_item); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_trait_alias(&mut self, item: &ItemTraitAlias) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.word("trait "); + self.ident(&item.ident); + self.generics(&item.generics); + self.word(" = "); + self.neverbreak(); + for bound in item.bounds.iter().delimited() { + if !bound.is_first { + self.space(); + self.word("+ "); + } + self.type_param_bound(&bound); + } + self.where_clause_semi(&item.generics.where_clause); + self.end(); + self.hardbreak(); + } + + fn item_type(&mut self, item: &ItemType) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.word("type "); + self.ident(&item.ident); + self.generics(&item.generics); + self.where_clause_oneline(&item.generics.where_clause); + self.word("= "); + self.neverbreak(); + self.ibox(-INDENT); + self.ty(&item.ty); + self.end(); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn item_union(&mut self, item: &ItemUnion) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + self.word("union "); + self.ident(&item.ident); + self.generics(&item.generics); + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + for field in &item.fields.named { + self.field(field); + self.word(","); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn item_use(&mut self, item: &ItemUse) { + self.outer_attrs(&item.attrs); + self.visibility(&item.vis); + self.word("use "); + if item.leading_colon.is_some() { + self.word("::"); + } + self.use_tree(&item.tree); + self.word(";"); + self.hardbreak(); + } + + #[cfg(not(feature = "verbatim"))] + fn item_verbatim(&mut self, item: &TokenStream) { + if !item.is_empty() { + unimplemented!("Item::Verbatim `{}`", item); + } + self.hardbreak(); + } + + #[cfg(feature = "verbatim")] + fn item_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::punctuated::Punctuated; + use syn::{ + braced, parenthesized, token, Attribute, Generics, Ident, Lifetime, Token, Visibility, + }; + use verbatim::{ + FlexibleItemConst, FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, + WhereClauseLocation, + }; + + enum ItemVerbatim { + Empty, + Ellipsis, + ConstFlexible(FlexibleItemConst), + FnFlexible(FlexibleItemFn), + ImplFlexible(ImplFlexible), + Macro2(Macro2), + StaticFlexible(FlexibleItemStatic), + TypeFlexible(FlexibleItemType), + UseBrace(UseBrace), + } + + struct ImplFlexible { + attrs: Vec, + vis: Visibility, + defaultness: bool, + unsafety: bool, + generics: Generics, + constness: ImplConstness, + negative_impl: bool, + trait_: Option, + self_ty: Type, + items: Vec, + } + + enum ImplConstness { + None, + MaybeConst, + Const, + } + + struct Macro2 { + attrs: Vec, + vis: Visibility, + ident: Ident, + args: Option, + body: TokenStream, + } + + struct UseBrace { + attrs: Vec, + vis: Visibility, + trees: Punctuated, + } + + struct RootUseTree { + leading_colon: Option, + inner: UseTree, + } + + impl Parse for ImplConstness { + fn parse(input: ParseStream) -> Result { + if input.parse::>()?.is_some() { + input.parse::()?; + Ok(ImplConstness::MaybeConst) + } else if input.parse::>()?.is_some() { + Ok(ImplConstness::Const) + } else { + Ok(ImplConstness::None) + } + } + } + + impl Parse for RootUseTree { + fn parse(input: ParseStream) -> Result { + Ok(RootUseTree { + leading_colon: input.parse()?, + inner: input.parse()?, + }) + } + } + + impl Parse for ItemVerbatim { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(ItemVerbatim::Empty); + } else if input.peek(Token![...]) { + input.parse::()?; + return Ok(ItemVerbatim::Ellipsis); + } + + let mut attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { + let defaultness = false; + let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; + Ok(ItemVerbatim::ConstFlexible(flexible_item)) + } else if input.peek(Token![const]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![unsafe]) && !input.peek2(Token![impl]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + let defaultness = false; + let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; + Ok(ItemVerbatim::FnFlexible(flexible_item)) + } else if lookahead.peek(Token![default]) + || input.peek(Token![unsafe]) + || lookahead.peek(Token![impl]) + { + let defaultness = input.parse::>()?.is_some(); + let unsafety = input.parse::>()?.is_some(); + input.parse::()?; + let has_generics = input.peek(Token![<]) + && (input.peek2(Token![>]) + || input.peek2(Token![#]) + || (input.peek2(Ident) || input.peek2(Lifetime)) + && (input.peek3(Token![:]) + || input.peek3(Token![,]) + || input.peek3(Token![>]) + || input.peek3(Token![=])) + || input.peek2(Token![const])); + let mut generics: Generics = if has_generics { + input.parse()? + } else { + Generics::default() + }; + let constness: ImplConstness = input.parse()?; + let negative_impl = + !input.peek2(token::Brace) && input.parse::>()?.is_some(); + let first_ty: Type = input.parse()?; + let (trait_, self_ty) = if input.parse::>()?.is_some() { + (Some(first_ty), input.parse()?) + } else { + (None, first_ty) + }; + generics.where_clause = input.parse()?; + let content; + braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + attrs.extend(inner_attrs); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + Ok(ItemVerbatim::ImplFlexible(ImplFlexible { + attrs, + vis, + defaultness, + unsafety, + generics, + constness, + negative_impl, + trait_, + self_ty, + items, + })) + } else if lookahead.peek(Token![macro]) { + input.parse::()?; + let ident: Ident = input.parse()?; + let args = if input.peek(token::Paren) { + let paren_content; + parenthesized!(paren_content in input); + Some(paren_content.parse::()?) + } else { + None + }; + let brace_content; + braced!(brace_content in input); + let body: TokenStream = brace_content.parse()?; + Ok(ItemVerbatim::Macro2(Macro2 { + attrs, + vis, + ident, + args, + body, + })) + } else if lookahead.peek(Token![static]) { + let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?; + Ok(ItemVerbatim::StaticFlexible(flexible_item)) + } else if lookahead.peek(Token![type]) { + let defaultness = false; + let flexible_item = FlexibleItemType::parse( + attrs, + vis, + defaultness, + input, + WhereClauseLocation::BeforeEq, + )?; + Ok(ItemVerbatim::TypeFlexible(flexible_item)) + } else if lookahead.peek(Token![use]) { + input.parse::()?; + let content; + braced!(content in input); + let trees = content.parse_terminated(RootUseTree::parse, Token![,])?; + input.parse::()?; + Ok(ItemVerbatim::UseBrace(UseBrace { attrs, vis, trees })) + } else { + Err(lookahead.error()) + } + } + } + + let item: ItemVerbatim = match syn::parse2(tokens.clone()) { + Ok(item) => item, + Err(_) => unimplemented!("Item::Verbatim `{}`", tokens), + }; + + match item { + ItemVerbatim::Empty => { + self.hardbreak(); + } + ItemVerbatim::Ellipsis => { + self.word("..."); + self.hardbreak(); + } + ItemVerbatim::ConstFlexible(item) => { + self.flexible_item_const(&item); + } + ItemVerbatim::FnFlexible(item) => { + self.flexible_item_fn(&item); + } + ItemVerbatim::ImplFlexible(item) => { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.ibox(-INDENT); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.defaultness { + self.word("default "); + } + if item.unsafety { + self.word("unsafe "); + } + self.word("impl"); + self.generics(&item.generics); + self.end(); + self.nbsp(); + match item.constness { + ImplConstness::None => {} + ImplConstness::MaybeConst => self.word("?const "), + ImplConstness::Const => self.word("const "), + } + if item.negative_impl { + self.word("!"); + } + if let Some(trait_) = &item.trait_ { + self.ty(trait_); + self.space(); + self.word("for "); + } + self.ty(&item.self_ty); + self.end(); + self.where_clause_for_body(&item.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for impl_item in &item.items { + self.impl_item(impl_item); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + ItemVerbatim::Macro2(item) => { + self.outer_attrs(&item.attrs); + self.visibility(&item.vis); + self.word("macro "); + self.ident(&item.ident); + if let Some(args) = &item.args { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + self.ibox(0); + self.macro_rules_tokens(args.clone(), true); + self.end(); + self.zerobreak(); + self.offset(-INDENT); + self.end(); + self.word(")"); + } + self.word(" {"); + if !item.body.is_empty() { + self.neverbreak(); + self.cbox(INDENT); + self.hardbreak(); + self.ibox(0); + self.macro_rules_tokens(item.body.clone(), false); + self.end(); + self.hardbreak(); + self.offset(-INDENT); + self.end(); + } + self.word("}"); + self.hardbreak(); + } + ItemVerbatim::StaticFlexible(item) => { + self.flexible_item_static(&item); + } + ItemVerbatim::TypeFlexible(item) => { + self.flexible_item_type(&item); + } + ItemVerbatim::UseBrace(item) => { + self.outer_attrs(&item.attrs); + self.visibility(&item.vis); + self.word("use "); + if item.trees.len() == 1 { + self.word("::"); + self.use_tree(&item.trees[0].inner); + } else { + self.cbox(INDENT); + self.word("{"); + self.zerobreak(); + self.ibox(0); + for use_tree in item.trees.iter().delimited() { + if use_tree.leading_colon.is_some() { + self.word("::"); + } + self.use_tree(&use_tree.inner); + if !use_tree.is_last { + self.word(","); + let mut use_tree = &use_tree.inner; + while let UseTree::Path(use_path) = use_tree { + use_tree = &use_path.tree; + } + if let UseTree::Group(_) = use_tree { + self.hardbreak(); + } else { + self.space(); + } + } + } + self.end(); + self.trailing_comma(true); + self.offset(-INDENT); + self.word("}"); + self.end(); + } + self.word(";"); + self.hardbreak(); + } + } + } + + fn use_tree(&mut self, use_tree: &UseTree) { + match use_tree { + UseTree::Path(use_path) => self.use_path(use_path), + UseTree::Name(use_name) => self.use_name(use_name), + UseTree::Rename(use_rename) => self.use_rename(use_rename), + UseTree::Glob(use_glob) => self.use_glob(use_glob), + UseTree::Group(use_group) => self.use_group(use_group), + } + } + + fn use_path(&mut self, use_path: &UsePath) { + self.ident(&use_path.ident); + self.word("::"); + self.use_tree(&use_path.tree); + } + + fn use_name(&mut self, use_name: &UseName) { + self.ident(&use_name.ident); + } + + fn use_rename(&mut self, use_rename: &UseRename) { + self.ident(&use_rename.ident); + self.word(" as "); + self.ident(&use_rename.rename); + } + + fn use_glob(&mut self, use_glob: &UseGlob) { + let _ = use_glob; + self.word("*"); + } + + fn use_group(&mut self, use_group: &UseGroup) { + if use_group.items.is_empty() { + self.word("{}"); + } else if use_group.items.len() == 1 + && match &use_group.items[0] { + UseTree::Rename(use_rename) => use_rename.ident != "self", + _ => true, + } + { + self.use_tree(&use_group.items[0]); + } else { + self.cbox(INDENT); + self.word("{"); + self.zerobreak(); + self.ibox(0); + for use_tree in use_group.items.iter().delimited() { + self.use_tree(&use_tree); + if !use_tree.is_last { + self.word(","); + let mut use_tree = *use_tree; + while let UseTree::Path(use_path) = use_tree { + use_tree = &use_path.tree; + } + if let UseTree::Group(_) = use_tree { + self.hardbreak(); + } else { + self.space(); + } + } + } + self.end(); + self.trailing_comma(true); + self.offset(-INDENT); + self.word("}"); + self.end(); + } + } + + fn foreign_item(&mut self, foreign_item: &ForeignItem) { + match foreign_item { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + ForeignItem::Fn(item) => self.foreign_item_fn(item), + ForeignItem::Static(item) => self.foreign_item_static(item), + ForeignItem::Type(item) => self.foreign_item_type(item), + ForeignItem::Macro(item) => self.foreign_item_macro(item), + ForeignItem::Verbatim(item) => self.foreign_item_verbatim(item), + _ => unimplemented!("unknown ForeignItem"), + } + } + + fn foreign_item_fn(&mut self, foreign_item: &ForeignItemFn) { + self.outer_attrs(&foreign_item.attrs); + self.cbox(INDENT); + self.visibility(&foreign_item.vis); + self.signature( + &foreign_item.sig, + #[cfg(feature = "verbatim")] + &verbatim::Safety::Disallowed, + ); + self.where_clause_semi(&foreign_item.sig.generics.where_clause); + self.end(); + self.hardbreak(); + } + + fn foreign_item_static(&mut self, foreign_item: &ForeignItemStatic) { + self.outer_attrs(&foreign_item.attrs); + self.cbox(0); + self.visibility(&foreign_item.vis); + self.word("static "); + self.static_mutability(&foreign_item.mutability); + self.ident(&foreign_item.ident); + self.word(": "); + self.ty(&foreign_item.ty); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn foreign_item_type(&mut self, foreign_item: &ForeignItemType) { + self.outer_attrs(&foreign_item.attrs); + self.cbox(0); + self.visibility(&foreign_item.vis); + self.word("type "); + self.ident(&foreign_item.ident); + self.generics(&foreign_item.generics); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn foreign_item_macro(&mut self, foreign_item: &ForeignItemMacro) { + self.outer_attrs(&foreign_item.attrs); + let semicolon = mac::requires_semi(&foreign_item.mac.delimiter); + self.mac(&foreign_item.mac, None, semicolon); + self.hardbreak(); + } + + #[cfg(not(feature = "verbatim"))] + fn foreign_item_verbatim(&mut self, foreign_item: &TokenStream) { + if !foreign_item.is_empty() { + unimplemented!("ForeignItem::Verbatim `{}`", foreign_item); + } + self.hardbreak(); + } + + #[cfg(feature = "verbatim")] + fn foreign_item_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{Abi, Attribute, Token, Visibility}; + use verbatim::{ + kw, FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, WhereClauseLocation, + }; + + enum ForeignItemVerbatim { + Empty, + Ellipsis, + FnFlexible(FlexibleItemFn), + StaticFlexible(FlexibleItemStatic), + TypeFlexible(FlexibleItemType), + } + + fn peek_signature(input: ParseStream) -> bool { + let fork = input.fork(); + fork.parse::>().is_ok() + && fork.parse::>().is_ok() + && ((fork.peek(kw::safe) && fork.parse::().is_ok()) + || fork.parse::>().is_ok()) + && fork.parse::>().is_ok() + && fork.peek(Token![fn]) + } + + impl Parse for ForeignItemVerbatim { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(ForeignItemVerbatim::Empty); + } else if input.peek(Token![...]) { + input.parse::()?; + return Ok(ForeignItemVerbatim::Ellipsis); + } + + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness = false; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![fn]) || peek_signature(input) { + let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; + Ok(ForeignItemVerbatim::FnFlexible(flexible_item)) + } else if lookahead.peek(Token![static]) + || ((input.peek(Token![unsafe]) || input.peek(kw::safe)) + && input.peek2(Token![static])) + { + let flexible_item = FlexibleItemStatic::parse(attrs, vis, input)?; + Ok(ForeignItemVerbatim::StaticFlexible(flexible_item)) + } else if lookahead.peek(Token![type]) { + let flexible_item = FlexibleItemType::parse( + attrs, + vis, + defaultness, + input, + WhereClauseLocation::Both, + )?; + Ok(ForeignItemVerbatim::TypeFlexible(flexible_item)) + } else { + Err(lookahead.error()) + } + } + } + + let foreign_item: ForeignItemVerbatim = match syn::parse2(tokens.clone()) { + Ok(foreign_item) => foreign_item, + Err(_) => unimplemented!("ForeignItem::Verbatim `{}`", tokens), + }; + + match foreign_item { + ForeignItemVerbatim::Empty => { + self.hardbreak(); + } + ForeignItemVerbatim::Ellipsis => { + self.word("..."); + self.hardbreak(); + } + ForeignItemVerbatim::FnFlexible(foreign_item) => { + self.flexible_item_fn(&foreign_item); + } + ForeignItemVerbatim::StaticFlexible(foreign_item) => { + self.flexible_item_static(&foreign_item); + } + ForeignItemVerbatim::TypeFlexible(foreign_item) => { + self.flexible_item_type(&foreign_item); + } + } + } + + fn trait_item(&mut self, trait_item: &TraitItem) { + match trait_item { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + TraitItem::Const(item) => self.trait_item_const(item), + TraitItem::Fn(item) => self.trait_item_fn(item), + TraitItem::Type(item) => self.trait_item_type(item), + TraitItem::Macro(item) => self.trait_item_macro(item), + TraitItem::Verbatim(item) => self.trait_item_verbatim(item), + _ => unimplemented!("unknown TraitItem"), + } + } + + fn trait_item_const(&mut self, trait_item: &TraitItemConst) { + self.outer_attrs(&trait_item.attrs); + self.cbox(0); + self.word("const "); + self.ident(&trait_item.ident); + self.generics(&trait_item.generics); + self.word(": "); + self.ty(&trait_item.ty); + if let Some((_eq_token, default)) = &trait_item.default { + self.word(" = "); + self.neverbreak(); + self.expr(default, FixupContext::NONE); + } + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn trait_item_fn(&mut self, trait_item: &TraitItemFn) { + self.outer_attrs(&trait_item.attrs); + self.cbox(INDENT); + self.signature( + &trait_item.sig, + #[cfg(feature = "verbatim")] + &verbatim::Safety::Disallowed, + ); + if let Some(block) = &trait_item.default { + self.where_clause_for_body(&trait_item.sig.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&trait_item.attrs); + for stmt in block.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } else { + self.where_clause_semi(&trait_item.sig.generics.where_clause); + self.end(); + } + self.hardbreak(); + } + + fn trait_item_type(&mut self, trait_item: &TraitItemType) { + self.outer_attrs(&trait_item.attrs); + self.cbox(INDENT); + self.word("type "); + self.ident(&trait_item.ident); + self.generics(&trait_item.generics); + for bound in trait_item.bounds.iter().delimited() { + if bound.is_first { + self.word(": "); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&bound); + } + if let Some((_eq_token, default)) = &trait_item.default { + self.word(" = "); + self.neverbreak(); + self.ibox(-INDENT); + self.ty(default); + self.end(); + } + self.where_clause_oneline_semi(&trait_item.generics.where_clause); + self.end(); + self.hardbreak(); + } + + fn trait_item_macro(&mut self, trait_item: &TraitItemMacro) { + self.outer_attrs(&trait_item.attrs); + let semicolon = mac::requires_semi(&trait_item.mac.delimiter); + self.mac(&trait_item.mac, None, semicolon); + self.hardbreak(); + } + + #[cfg(not(feature = "verbatim"))] + fn trait_item_verbatim(&mut self, trait_item: &TokenStream) { + if !trait_item.is_empty() { + unimplemented!("TraitItem::Verbatim `{}`", trait_item); + } + self.hardbreak(); + } + + #[cfg(feature = "verbatim")] + fn trait_item_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{Attribute, Ident, Token, Visibility}; + use verbatim::{FlexibleItemConst, FlexibleItemType, WhereClauseLocation}; + + enum TraitItemVerbatim { + Empty, + Ellipsis, + ConstFlexible(FlexibleItemConst), + TypeFlexible(FlexibleItemType), + PubOrDefault(PubOrDefaultTraitItem), + } + + struct PubOrDefaultTraitItem { + attrs: Vec, + vis: Visibility, + defaultness: bool, + trait_item: TraitItem, + } + + impl Parse for TraitItemVerbatim { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(TraitItemVerbatim::Empty); + } else if input.peek(Token![...]) { + input.parse::()?; + return Ok(TraitItemVerbatim::Ellipsis); + } + + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness = input.parse::>()?.is_some(); + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { + let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; + Ok(TraitItemVerbatim::ConstFlexible(flexible_item)) + } else if lookahead.peek(Token![type]) { + let flexible_item = FlexibleItemType::parse( + attrs, + vis, + defaultness, + input, + WhereClauseLocation::AfterEq, + )?; + Ok(TraitItemVerbatim::TypeFlexible(flexible_item)) + } else if (input.peek(Token![const]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn])) + && (!matches!(vis, Visibility::Inherited) || defaultness) + { + Ok(TraitItemVerbatim::PubOrDefault(PubOrDefaultTraitItem { + attrs, + vis, + defaultness, + trait_item: input.parse()?, + })) + } else { + Err(lookahead.error()) + } + } + } + + let impl_item: TraitItemVerbatim = match syn::parse2(tokens.clone()) { + Ok(impl_item) => impl_item, + Err(_) => unimplemented!("TraitItem::Verbatim `{}`", tokens), + }; + + match impl_item { + TraitItemVerbatim::Empty => { + self.hardbreak(); + } + TraitItemVerbatim::Ellipsis => { + self.word("..."); + self.hardbreak(); + } + TraitItemVerbatim::ConstFlexible(trait_item) => { + self.flexible_item_const(&trait_item); + } + TraitItemVerbatim::TypeFlexible(trait_item) => { + self.flexible_item_type(&trait_item); + } + TraitItemVerbatim::PubOrDefault(trait_item) => { + self.outer_attrs(&trait_item.attrs); + self.visibility(&trait_item.vis); + if trait_item.defaultness { + self.word("default "); + } + self.trait_item(&trait_item.trait_item); + } + } + } + + fn impl_item(&mut self, impl_item: &ImplItem) { + match impl_item { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + ImplItem::Const(item) => self.impl_item_const(item), + ImplItem::Fn(item) => self.impl_item_fn(item), + ImplItem::Type(item) => self.impl_item_type(item), + ImplItem::Macro(item) => self.impl_item_macro(item), + ImplItem::Verbatim(item) => self.impl_item_verbatim(item), + _ => unimplemented!("unknown ImplItem"), + } + } + + fn impl_item_const(&mut self, impl_item: &ImplItemConst) { + self.outer_attrs(&impl_item.attrs); + self.cbox(0); + self.visibility(&impl_item.vis); + if impl_item.defaultness.is_some() { + self.word("default "); + } + self.word("const "); + self.ident(&impl_item.ident); + self.generics(&impl_item.generics); + self.word(": "); + self.ty(&impl_item.ty); + self.word(" = "); + self.neverbreak(); + self.expr(&impl_item.expr, FixupContext::NONE); + self.word(";"); + self.end(); + self.hardbreak(); + } + + fn impl_item_fn(&mut self, impl_item: &ImplItemFn) { + self.outer_attrs(&impl_item.attrs); + self.cbox(INDENT); + self.visibility(&impl_item.vis); + if impl_item.defaultness.is_some() { + self.word("default "); + } + self.signature( + &impl_item.sig, + #[cfg(feature = "verbatim")] + &verbatim::Safety::Disallowed, + ); + self.where_clause_for_body(&impl_item.sig.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&impl_item.attrs); + for stmt in impl_item.block.stmts.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + self.hardbreak(); + } + + fn impl_item_type(&mut self, impl_item: &ImplItemType) { + self.outer_attrs(&impl_item.attrs); + self.cbox(INDENT); + self.visibility(&impl_item.vis); + if impl_item.defaultness.is_some() { + self.word("default "); + } + self.word("type "); + self.ident(&impl_item.ident); + self.generics(&impl_item.generics); + self.word(" = "); + self.neverbreak(); + self.ibox(-INDENT); + self.ty(&impl_item.ty); + self.end(); + self.where_clause_oneline_semi(&impl_item.generics.where_clause); + self.end(); + self.hardbreak(); + } + + fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) { + self.outer_attrs(&impl_item.attrs); + let semicolon = mac::requires_semi(&impl_item.mac.delimiter); + self.mac(&impl_item.mac, None, semicolon); + self.hardbreak(); + } + + #[cfg(not(feature = "verbatim"))] + fn impl_item_verbatim(&mut self, impl_item: &TokenStream) { + if !impl_item.is_empty() { + unimplemented!("ImplItem::Verbatim `{}`", impl_item); + } + self.hardbreak(); + } + + #[cfg(feature = "verbatim")] + fn impl_item_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{Attribute, Ident, Token, Visibility}; + use verbatim::{FlexibleItemConst, FlexibleItemFn, FlexibleItemType, WhereClauseLocation}; + + enum ImplItemVerbatim { + Empty, + Ellipsis, + ConstFlexible(FlexibleItemConst), + FnFlexible(FlexibleItemFn), + TypeFlexible(FlexibleItemType), + } + + impl Parse for ImplItemVerbatim { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(ImplItemVerbatim::Empty); + } else if input.peek(Token![...]) { + input.parse::()?; + return Ok(ImplItemVerbatim::Ellipsis); + } + + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness = input.parse::>()?.is_some(); + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![const]) && (input.peek2(Ident) || input.peek2(Token![_])) { + let flexible_item = FlexibleItemConst::parse(attrs, vis, defaultness, input)?; + Ok(ImplItemVerbatim::ConstFlexible(flexible_item)) + } else if input.peek(Token![const]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + let flexible_item = FlexibleItemFn::parse(attrs, vis, defaultness, input)?; + Ok(ImplItemVerbatim::FnFlexible(flexible_item)) + } else if lookahead.peek(Token![type]) { + let flexible_item = FlexibleItemType::parse( + attrs, + vis, + defaultness, + input, + WhereClauseLocation::AfterEq, + )?; + Ok(ImplItemVerbatim::TypeFlexible(flexible_item)) + } else { + Err(lookahead.error()) + } + } + } + + let impl_item: ImplItemVerbatim = match syn::parse2(tokens.clone()) { + Ok(impl_item) => impl_item, + Err(_) => unimplemented!("ImplItem::Verbatim `{}`", tokens), + }; + + match impl_item { + ImplItemVerbatim::Empty => { + self.hardbreak(); + } + ImplItemVerbatim::Ellipsis => { + self.word("..."); + self.hardbreak(); + } + ImplItemVerbatim::ConstFlexible(impl_item) => { + self.flexible_item_const(&impl_item); + } + ImplItemVerbatim::FnFlexible(impl_item) => { + self.flexible_item_fn(&impl_item); + } + ImplItemVerbatim::TypeFlexible(impl_item) => { + self.flexible_item_type(&impl_item); + } + } + } + + fn signature( + &mut self, + signature: &Signature, + #[cfg(feature = "verbatim")] safety: &verbatim::Safety, + ) { + if signature.constness.is_some() { + self.word("const "); + } + if signature.asyncness.is_some() { + self.word("async "); + } + #[cfg(feature = "verbatim")] + { + if let verbatim::Safety::Disallowed = safety { + if signature.unsafety.is_some() { + self.word("unsafe "); + } + } else { + self.safety(safety); + } + } + #[cfg(not(feature = "verbatim"))] + { + if signature.unsafety.is_some() { + self.word("unsafe "); + } + } + if let Some(abi) = &signature.abi { + self.abi(abi); + } + self.word("fn "); + self.ident(&signature.ident); + self.generics(&signature.generics); + self.word("("); + self.neverbreak(); + self.cbox(0); + self.zerobreak(); + for input in signature.inputs.iter().delimited() { + self.fn_arg(&input); + let is_last = input.is_last && signature.variadic.is_none(); + self.trailing_comma(is_last); + } + if let Some(variadic) = &signature.variadic { + self.variadic(variadic); + self.zerobreak(); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + self.cbox(-INDENT); + self.return_type(&signature.output); + self.end(); + } + + fn fn_arg(&mut self, fn_arg: &FnArg) { + match fn_arg { + FnArg::Receiver(receiver) => self.receiver(receiver), + FnArg::Typed(pat_type) => self.pat_type(pat_type), + } + } + + fn receiver(&mut self, receiver: &Receiver) { + self.outer_attrs(&receiver.attrs); + if let Some((_ampersand, lifetime)) = &receiver.reference { + self.word("&"); + if let Some(lifetime) = lifetime { + self.lifetime(lifetime); + self.nbsp(); + } + } + if receiver.mutability.is_some() { + self.word("mut "); + } + self.word("self"); + if receiver.colon_token.is_some() { + self.word(": "); + self.ty(&receiver.ty); + } else { + let consistent = match (&receiver.reference, &receiver.mutability, &*receiver.ty) { + (Some(_), mutability, Type::Reference(ty)) => { + mutability.is_some() == ty.mutability.is_some() + && match &*ty.elem { + Type::Path(ty) => ty.qself.is_none() && ty.path.is_ident("Self"), + _ => false, + } + } + (None, _, Type::Path(ty)) => ty.qself.is_none() && ty.path.is_ident("Self"), + _ => false, + }; + if !consistent { + self.word(": "); + self.ty(&receiver.ty); + } + } + } + + fn variadic(&mut self, variadic: &Variadic) { + self.outer_attrs(&variadic.attrs); + if let Some((pat, _colon)) = &variadic.pat { + self.pat(pat); + self.word(": "); + } + self.word("..."); + } + + fn static_mutability(&mut self, mutability: &StaticMutability) { + match mutability { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + StaticMutability::Mut(_) => self.word("mut "), + StaticMutability::None => {} + _ => unimplemented!("unknown StaticMutability"), + } + } +} + +#[cfg(feature = "verbatim")] +mod verbatim { + use crate::algorithm::Printer; + use crate::fixup::FixupContext; + use crate::iter::IterDelimited; + use crate::INDENT; + use syn::ext::IdentExt; + use syn::parse::{Parse, ParseStream, Result}; + use syn::{ + braced, token, Attribute, Block, Expr, Generics, Ident, Signature, StaticMutability, Stmt, + Token, Type, TypeParamBound, Visibility, WhereClause, + }; + + pub mod kw { + syn::custom_keyword!(safe); + } + + pub struct FlexibleItemConst { + pub attrs: Vec, + pub vis: Visibility, + pub defaultness: bool, + pub ident: Ident, + pub generics: Generics, + pub ty: Type, + pub value: Option, + } + + pub struct FlexibleItemFn { + pub attrs: Vec, + pub vis: Visibility, + pub defaultness: bool, + pub safety: Safety, + pub sig: Signature, + pub body: Option>, + } + + pub struct FlexibleItemStatic { + pub attrs: Vec, + pub vis: Visibility, + pub safety: Safety, + pub mutability: StaticMutability, + pub ident: Ident, + pub ty: Option, + pub expr: Option, + } + + pub struct FlexibleItemType { + pub attrs: Vec, + pub vis: Visibility, + pub defaultness: bool, + pub ident: Ident, + pub generics: Generics, + pub bounds: Vec, + pub definition: Option, + pub where_clause_after_eq: Option, + } + + pub enum Safety { + Unsafe, + Safe, + Default, + Disallowed, + } + + pub enum WhereClauseLocation { + // type Ty where T: 'static = T; + BeforeEq, + // type Ty = T where T: 'static; + AfterEq, + // TODO: goes away once the migration period on rust-lang/rust#89122 is over + Both, + } + + impl FlexibleItemConst { + pub fn parse( + attrs: Vec, + vis: Visibility, + defaultness: bool, + input: ParseStream, + ) -> Result { + input.parse::()?; + let ident = input.call(Ident::parse_any)?; + let mut generics: Generics = input.parse()?; + input.parse::()?; + let ty: Type = input.parse()?; + let value = if input.parse::>()?.is_some() { + let expr: Expr = input.parse()?; + Some(expr) + } else { + None + }; + generics.where_clause = input.parse()?; + input.parse::()?; + + Ok(FlexibleItemConst { + attrs, + vis, + defaultness, + ident, + generics, + ty, + value, + }) + } + } + + impl FlexibleItemFn { + pub fn parse( + mut attrs: Vec, + vis: Visibility, + defaultness: bool, + input: ParseStream, + ) -> Result { + let constness: Option = input.parse()?; + let asyncness: Option = input.parse()?; + let safety: Safety = input.parse()?; + + let lookahead = input.lookahead1(); + let sig: Signature = if lookahead.peek(Token![extern]) || lookahead.peek(Token![fn]) { + input.parse()? + } else { + return Err(lookahead.error()); + }; + + let lookahead = input.lookahead1(); + let body = if lookahead.peek(Token![;]) { + input.parse::()?; + None + } else if lookahead.peek(token::Brace) { + let content; + braced!(content in input); + attrs.extend(content.call(Attribute::parse_inner)?); + Some(content.call(Block::parse_within)?) + } else { + return Err(lookahead.error()); + }; + + Ok(FlexibleItemFn { + attrs, + vis, + defaultness, + safety, + sig: Signature { + constness, + asyncness, + unsafety: None, + ..sig + }, + body, + }) + } + } + + impl FlexibleItemStatic { + pub fn parse(attrs: Vec, vis: Visibility, input: ParseStream) -> Result { + let safety: Safety = input.parse()?; + input.parse::()?; + let mutability: StaticMutability = input.parse()?; + let ident = input.parse()?; + + let lookahead = input.lookahead1(); + let has_type = lookahead.peek(Token![:]); + let has_expr = lookahead.peek(Token![=]); + if !has_type && !has_expr { + return Err(lookahead.error()); + } + + let ty: Option = if has_type { + input.parse::()?; + input.parse().map(Some)? + } else { + None + }; + + let expr: Option = if input.parse::>()?.is_some() { + input.parse().map(Some)? + } else { + None + }; + + input.parse::()?; + + Ok(FlexibleItemStatic { + attrs, + vis, + safety, + mutability, + ident, + ty, + expr, + }) + } + } + + impl FlexibleItemType { + pub fn parse( + attrs: Vec, + vis: Visibility, + defaultness: bool, + input: ParseStream, + where_clause_location: WhereClauseLocation, + ) -> Result { + input.parse::()?; + let ident: Ident = input.parse()?; + let mut generics: Generics = input.parse()?; + + let mut bounds = Vec::new(); + if input.parse::>()?.is_some() { + loop { + if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { + break; + } + bounds.push(input.parse::()?); + if input.peek(Token![where]) || input.peek(Token![=]) || input.peek(Token![;]) { + break; + } + input.parse::()?; + } + } + + match where_clause_location { + WhereClauseLocation::BeforeEq | WhereClauseLocation::Both => { + generics.where_clause = input.parse()?; + } + WhereClauseLocation::AfterEq => {} + } + + let definition = if input.parse::>()?.is_some() { + Some(input.parse()?) + } else { + None + }; + + let where_clause_after_eq = match where_clause_location { + WhereClauseLocation::AfterEq | WhereClauseLocation::Both + if generics.where_clause.is_none() => + { + input.parse()? + } + _ => None, + }; + + input.parse::()?; + + Ok(FlexibleItemType { + attrs, + vis, + defaultness, + ident, + generics, + bounds, + definition, + where_clause_after_eq, + }) + } + } + + impl Parse for Safety { + fn parse(input: ParseStream) -> Result { + if input.peek(Token![unsafe]) { + input.parse::()?; + Ok(Safety::Unsafe) + } else if input.peek(kw::safe) { + input.parse::()?; + Ok(Safety::Safe) + } else { + Ok(Safety::Default) + } + } + } + + impl Printer { + pub fn flexible_item_const(&mut self, item: &FlexibleItemConst) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.defaultness { + self.word("default "); + } + self.word("const "); + self.ident(&item.ident); + self.generics(&item.generics); + self.word(": "); + self.cbox(-INDENT); + self.ty(&item.ty); + self.end(); + if let Some(value) = &item.value { + self.word(" = "); + self.neverbreak(); + self.ibox(-INDENT); + self.expr(value, FixupContext::NONE); + self.end(); + } + self.where_clause_oneline_semi(&item.generics.where_clause); + self.end(); + self.hardbreak(); + } + + pub fn flexible_item_fn(&mut self, item: &FlexibleItemFn) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.defaultness { + self.word("default "); + } + self.signature(&item.sig, &item.safety); + if let Some(body) = &item.body { + self.where_clause_for_body(&item.sig.generics.where_clause); + self.word("{"); + self.hardbreak_if_nonempty(); + self.inner_attrs(&item.attrs); + for stmt in body.iter().delimited() { + self.stmt(&stmt, stmt.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } else { + self.where_clause_semi(&item.sig.generics.where_clause); + self.end(); + } + self.hardbreak(); + } + + pub fn flexible_item_static(&mut self, item: &FlexibleItemStatic) { + self.outer_attrs(&item.attrs); + self.cbox(0); + self.visibility(&item.vis); + self.safety(&item.safety); + self.word("static "); + self.static_mutability(&item.mutability); + self.ident(&item.ident); + if let Some(ty) = &item.ty { + self.word(": "); + self.ty(ty); + } + if let Some(expr) = &item.expr { + self.word(" = "); + self.neverbreak(); + self.expr(expr, FixupContext::NONE); + } + self.word(";"); + self.end(); + self.hardbreak(); + } + + pub fn flexible_item_type(&mut self, item: &FlexibleItemType) { + self.outer_attrs(&item.attrs); + self.cbox(INDENT); + self.visibility(&item.vis); + if item.defaultness { + self.word("default "); + } + self.word("type "); + self.ident(&item.ident); + self.generics(&item.generics); + for bound in item.bounds.iter().delimited() { + if bound.is_first { + self.word(": "); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&bound); + } + if let Some(definition) = &item.definition { + self.where_clause_oneline(&item.generics.where_clause); + self.word("= "); + self.neverbreak(); + self.ibox(-INDENT); + self.ty(definition); + self.end(); + self.where_clause_oneline_semi(&item.where_clause_after_eq); + } else { + self.where_clause_oneline_semi(&item.generics.where_clause); + } + self.end(); + self.hardbreak(); + } + + pub fn safety(&mut self, safety: &Safety) { + match safety { + Safety::Unsafe => self.word("unsafe "), + Safety::Safe => self.word("safe "), + Safety::Default => {} + Safety::Disallowed => unreachable!(), + } + } + } +} diff --git a/vendor/prettyplease/src/iter.rs b/vendor/prettyplease/src/iter.rs new file mode 100644 index 00000000..702c653f --- /dev/null +++ b/vendor/prettyplease/src/iter.rs @@ -0,0 +1,46 @@ +use std::iter::Peekable; +use std::ops::Deref; + +pub struct Delimited { + is_first: bool, + iter: Peekable, +} + +pub trait IterDelimited: Iterator + Sized { + fn delimited(self) -> Delimited { + Delimited { + is_first: true, + iter: self.peekable(), + } + } +} + +impl IterDelimited for I {} + +pub struct IteratorItem { + value: T, + pub is_first: bool, + pub is_last: bool, +} + +impl Iterator for Delimited { + type Item = IteratorItem; + + fn next(&mut self) -> Option { + let item = IteratorItem { + value: self.iter.next()?, + is_first: self.is_first, + is_last: self.iter.peek().is_none(), + }; + self.is_first = false; + Some(item) + } +} + +impl Deref for IteratorItem { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} diff --git a/vendor/prettyplease/src/lib.rs b/vendor/prettyplease/src/lib.rs new file mode 100644 index 00000000..ee2b048d --- /dev/null +++ b/vendor/prettyplease/src/lib.rs @@ -0,0 +1,385 @@ +//! [![github]](https://github.com/dtolnay/prettyplease) [![crates-io]](https://crates.io/crates/prettyplease) [![docs-rs]](https://docs.rs/prettyplease) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! **prettyplease::unparse** — a minimal `syn` syntax tree pretty-printer +//! +//!
+//! +//! # Overview +//! +//! This is a pretty-printer to turn a `syn` syntax tree into a `String` of +//! well-formatted source code. In contrast to rustfmt, this library is intended +//! to be suitable for arbitrary generated code. +//! +//! Rustfmt prioritizes high-quality output that is impeccable enough that you'd +//! be comfortable spending your career staring at its output — but that +//! means some heavyweight algorithms, and it has a tendency to bail out on code +//! that is hard to format (for example [rustfmt#3697], and there are dozens +//! more issues like it). That's not necessarily a big deal for human-generated +//! code because when code gets highly nested, the human will naturally be +//! inclined to refactor into more easily formattable code. But for generated +//! code, having the formatter just give up leaves it totally unreadable. +//! +//! [rustfmt#3697]: https://github.com/rust-lang/rustfmt/issues/3697 +//! +//! This library is designed using the simplest possible algorithm and data +//! structures that can deliver about 95% of the quality of rustfmt-formatted +//! output. In my experience testing real-world code, approximately 97-98% of +//! output lines come out identical between rustfmt's formatting and this +//! crate's. The rest have slightly different linebreak decisions, but still +//! clearly follow the dominant modern Rust style. +//! +//! The tradeoffs made by this crate are a good fit for generated code that you +//! will *not* spend your career staring at. For example, the output of +//! `bindgen`, or the output of `cargo-expand`. In those cases it's more +//! important that the whole thing be formattable without the formatter giving +//! up, than that it be flawless. +//! +//!
+//! +//! # Feature matrix +//! +//! Here are a few superficial comparisons of this crate against the AST +//! pretty-printer built into rustc, and rustfmt. The sections below go into +//! more detail comparing the output of each of these libraries. +//! +//! | | prettyplease | rustc | rustfmt | +//! |:---|:---:|:---:|:---:| +//! | non-pathological behavior on big or generated code | 💚 | ❌ | ❌ | +//! | idiomatic modern formatting ("locally indistinguishable from rustfmt") | 💚 | ❌ | 💚 | +//! | throughput | 60 MB/s | 39 MB/s | 2.8 MB/s | +//! | number of dependencies | 3 | 72 | 66 | +//! | compile time including dependencies | 2.4 sec | 23.1 sec | 29.8 sec | +//! | buildable using a stable Rust compiler | 💚 | ❌ | ❌ | +//! | published to crates.io | 💚 | ❌ | ❌ | +//! | extensively configurable output | ❌ | ❌ | 💚 | +//! | intended to accommodate hand-maintained source code | ❌ | ❌ | 💚 | +//! +//!
+//! +//! # Comparison to rustfmt +//! +//! - [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) +//! - [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) +//! - [output.rustfmt.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustfmt.rs) +//! +//! If you weren't told which output file is which, it would be practically +//! impossible to tell — **except** for line 435 in the rustfmt output, +//! which is more than 1000 characters long because rustfmt just gave up +//! formatting that part of the file: +//! +//! ``` +//! # const _: &str = stringify! {{{ +//! match segments[5] { +//! 0 => write!(f, "::{}", ipv4), +//! 0xffff => write!(f, "::ffff:{}", ipv4), +//! _ => unreachable!(), +//! } +//! } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } +//! } else { +//! const IPV6_BUF_LEN: usize = (4 * 8) + 7; +//! let mut buf = [0u8; IPV6_BUF_LEN]; +//! let mut buf_slice = &mut buf[..]; +//! # }}; +//! ``` +//! +//! This is a pretty typical manifestation of rustfmt bailing out in generated +//! code — a chunk of the input ends up on one line. The other +//! manifestation is that you're working on some code, running rustfmt on save +//! like a conscientious developer, but after a while notice it isn't doing +//! anything. You introduce an intentional formatting issue, like a stray indent +//! or semicolon, and run rustfmt to check your suspicion. Nope, it doesn't get +//! cleaned up — rustfmt is just not formatting the part of the file you +//! are working on. +//! +//! The prettyplease library is designed to have no pathological cases that +//! force a bail out; the entire input you give it will get formatted in some +//! "good enough" form. +//! +//! Separately, rustfmt can be problematic to integrate into projects. It's +//! written using rustc's internal syntax tree, so it can't be built by a stable +//! compiler. Its releases are not regularly published to crates.io, so in Cargo +//! builds you'd need to depend on it as a git dependency, which precludes +//! publishing your crate to crates.io also. You can shell out to a `rustfmt` +//! binary, but that'll be whatever rustfmt version is installed on each +//! developer's system (if any), which can lead to spurious diffs in checked-in +//! generated code formatted by different versions. In contrast prettyplease is +//! designed to be easy to pull in as a library, and compiles fast. +//! +//!
+//! +//! # Comparison to rustc_ast_pretty +//! +//! - [input.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/input.rs) +//! - [output.prettyplease.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.prettyplease.rs) +//! - [output.rustc.rs](https://github.com/dtolnay/prettyplease/blob/0.1.0/examples/output.rustc.rs) +//! +//! This is the pretty-printer that gets used when rustc prints source code, +//! such as `rustc -Zunpretty=expanded`. It's used also by the standard +//! library's `stringify!` when stringifying an interpolated macro_rules AST +//! fragment, like an $:expr, and transitively by `dbg!` and many macros in the +//! ecosystem. +//! +//! Rustc's formatting is mostly okay, but does not hew closely to the dominant +//! contemporary style of Rust formatting. Some things wouldn't ever be written +//! on one line, like this `match` expression, and certainly not with a comma in +//! front of the closing brace: +//! +//! ``` +//! # const _: &str = stringify! { +//! fn eq(&self, other: &IpAddr) -> bool { +//! match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } +//! } +//! # }; +//! ``` +//! +//! Some places use non-multiple-of-4 indentation, which is definitely not the +//! norm: +//! +//! ``` +//! # const _: &str = stringify! { +//! pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { +//! let [a, b, c, d] = self.octets(); +//! Ipv6Addr{inner: +//! c::in6_addr{s6_addr: +//! [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, +//! 0xFF, a, b, c, d],},} +//! } +//! # }; +//! ``` +//! +//! And although there isn't an egregious example of it in the link because the +//! input code is pretty tame, in general rustc_ast_pretty has pathological +//! behavior on generated code. It has a tendency to use excessive horizontal +//! indentation and rapidly run out of width: +//! +//! ``` +//! # const _: &str = stringify! { +//! ::std::io::_print(::core::fmt::Arguments::new_v1(&[""], +//! &match (&msg,) { +//! _args => +//! [::core::fmt::ArgumentV1::new(_args.0, +//! ::core::fmt::Display::fmt)], +//! })); +//! # }; +//! ``` +//! +//! The snippets above are clearly different from modern rustfmt style. In +//! contrast, prettyplease is designed to have output that is practically +//! indistinguishable from rustfmt-formatted code. +//! +//!
+//! +//! # Example +//! +//! ``` +//! // [dependencies] +//! // prettyplease = "0.2" +//! // syn = { version = "2", default-features = false, features = ["full", "parsing"] } +//! +//! const INPUT: &str = stringify! { +//! use crate::{ +//! lazy::{Lazy, SyncLazy, SyncOnceCell}, panic, +//! sync::{ atomic::{AtomicUsize, Ordering::SeqCst}, +//! mpsc::channel, Mutex, }, +//! thread, +//! }; +//! impl Into for T where U: From { +//! fn into(self) -> U { U::from(self) } +//! } +//! }; +//! +//! fn main() { +//! let syntax_tree = syn::parse_file(INPUT).unwrap(); +//! let formatted = prettyplease::unparse(&syntax_tree); +//! print!("{}", formatted); +//! } +//! ``` +//! +//!
+//! +//! # Algorithm notes +//! +//! The approach and terminology used in the implementation are derived from +//! [*Derek C. Oppen, "Pretty Printing" (1979)*][paper], on which +//! rustc_ast_pretty is also based, and from rustc_ast_pretty's implementation +//! written by Graydon Hoare in 2011 (and modernized over the years by dozens of +//! volunteer maintainers). +//! +//! [paper]: http://i.stanford.edu/pub/cstr/reports/cs/tr/79/770/CS-TR-79-770.pdf +//! +//! The paper describes two language-agnostic interacting procedures `Scan()` +//! and `Print()`. Language-specific code decomposes an input data structure +//! into a stream of `string` and `break` tokens, and `begin` and `end` tokens +//! for grouping. Each `begin`–`end` range may be identified as either +//! "consistent breaking" or "inconsistent breaking". If a group is consistently +//! breaking, then if the whole contents do not fit on the line, *every* `break` +//! token in the group will receive a linebreak. This is appropriate, for +//! example, for Rust struct literals, or arguments of a function call. If a +//! group is inconsistently breaking, then the `string` tokens in the group are +//! greedily placed on the line until out of space, and linebroken only at those +//! `break` tokens for which the next string would not fit. For example, this is +//! appropriate for the contents of a braced `use` statement in Rust. +//! +//! Scan's job is to efficiently accumulate sizing information about groups and +//! breaks. For every `begin` token we compute the distance to the matched `end` +//! token, and for every `break` we compute the distance to the next `break`. +//! The algorithm uses a ringbuffer to hold tokens whose size is not yet +//! ascertained. The maximum size of the ringbuffer is bounded by the target +//! line length and does not grow indefinitely, regardless of deep nesting in +//! the input stream. That's because once a group is sufficiently big, the +//! precise size can no longer make a difference to linebreak decisions and we +//! can effectively treat it as "infinity". +//! +//! Print's job is to use the sizing information to efficiently assign a +//! "broken" or "not broken" status to every `begin` token. At that point the +//! output is easily constructed by concatenating `string` tokens and breaking +//! at `break` tokens contained within a broken group. +//! +//! Leveraging these primitives (i.e. cleverly placing the all-or-nothing +//! consistent breaks and greedy inconsistent breaks) to yield +//! rustfmt-compatible formatting for all of Rust's syntax tree nodes is a fun +//! challenge. +//! +//! Here is a visualization of some Rust tokens fed into the pretty printing +//! algorithm. Consistently breaking `begin`—`end` pairs are represented +//! by `«`⁠`»`, inconsistently breaking by `‹`⁠`›`, `break` by `·`, +//! and the rest of the non-whitespace are `string`. +//! +//! ```text +//! use crate::«{· +//! ‹ lazy::«{·‹Lazy,· SyncLazy,· SyncOnceCell›·}»,· +//! panic,· +//! sync::«{· +//! ‹ atomic::«{·‹AtomicUsize,· Ordering::SeqCst›·}»,· +//! mpsc::channel,· Mutex›,· +//! }»,· +//! thread›,· +//! }»;· +//! «‹«impl<«·T‹›,· U‹›·»>» Into<«·U·»>· for T›· +//! where· +//! U:‹ From<«·T·»>›,· +//! {· +//! « fn into(·«·self·») -> U {· +//! ‹ U::from(«·self·»)›· +//! » }· +//! »}· +//! ``` +//! +//! The algorithm described in the paper is not quite sufficient for producing +//! well-formatted Rust code that is locally indistinguishable from rustfmt's +//! style. The reason is that in the paper, the complete non-whitespace contents +//! are assumed to be independent of linebreak decisions, with Scan and Print +//! being only in control of the whitespace (spaces and line breaks). In Rust as +//! idiomatically formatted by rustfmt, that is not the case. Trailing commas +//! are one example; the punctuation is only known *after* the broken vs +//! non-broken status of the surrounding group is known: +//! +//! ``` +//! # struct Struct { x: u64, y: bool } +//! # let xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 0; +//! # let yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy = true; +//! # +//! let _ = Struct { x: 0, y: true }; +//! +//! let _ = Struct { +//! x: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +//! y: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy, //<- trailing comma if the expression wrapped +//! }; +//! ``` +//! +//! The formatting of `match` expressions is another case; we want small arms on +//! the same line as the pattern, and big arms wrapped in a brace. The presence +//! of the brace punctuation, comma, and semicolon are all dependent on whether +//! the arm fits on the line: +//! +//! ``` +//! # struct Entry { nanos: u32 } +//! # let total_nanos = 0u64; +//! # let mut total_secs = 0u64; +//! # let tmp; +//! # let entry = Entry { nanos: 0 }; +//! # const NANOS_PER_SEC: u32 = 1_000_000_000; +//! # +//! match total_nanos.checked_add(entry.nanos as u64) { +//! Some(n) => tmp = n, //<- small arm, inline with comma +//! None => { +//! total_secs = total_secs +//! .checked_add(total_nanos / NANOS_PER_SEC as u64) +//! .expect("overflow in iter::sum over durations"); +//! } //<- big arm, needs brace added, and also semicolon^ +//! } +//! ``` +//! +//! The printing algorithm implementation in this crate accommodates all of +//! these situations with conditional punctuation tokens whose selection can be +//! deferred and populated after it's known that the group is or is not broken. + +#![doc(html_root_url = "https://docs.rs/prettyplease/0.2.35")] +#![allow( + clippy::bool_to_int_with_if, + clippy::cast_possible_wrap, + clippy::cast_sign_loss, + clippy::derive_partial_eq_without_eq, + clippy::doc_markdown, + clippy::enum_glob_use, + clippy::items_after_statements, + clippy::let_underscore_untyped, + clippy::match_like_matches_macro, + clippy::match_same_arms, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::needless_pass_by_value, + clippy::ref_option, + clippy::similar_names, + clippy::struct_excessive_bools, + clippy::too_many_lines, + clippy::unused_self, + clippy::vec_init_then_push +)] +#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))] + +mod algorithm; +mod attr; +mod classify; +mod convenience; +mod data; +mod expr; +mod file; +mod fixup; +mod generics; +mod item; +mod iter; +mod lifetime; +mod lit; +mod mac; +mod pat; +mod path; +mod precedence; +mod ring; +mod stmt; +mod token; +mod ty; + +use crate::algorithm::Printer; +use syn::File; + +// Target line width. +const MARGIN: isize = 89; + +// Number of spaces increment at each level of block indentation. +const INDENT: isize = 4; + +// Every line is allowed at least this much space, even if highly indented. +const MIN_SPACE: isize = 60; + +pub fn unparse(file: &File) -> String { + let mut p = Printer::new(); + p.file(file); + p.eof() +} diff --git a/vendor/prettyplease/src/lifetime.rs b/vendor/prettyplease/src/lifetime.rs new file mode 100644 index 00000000..665caa32 --- /dev/null +++ b/vendor/prettyplease/src/lifetime.rs @@ -0,0 +1,9 @@ +use crate::algorithm::Printer; +use syn::Lifetime; + +impl Printer { + pub fn lifetime(&mut self, lifetime: &Lifetime) { + self.word("'"); + self.ident(&lifetime.ident); + } +} diff --git a/vendor/prettyplease/src/lit.rs b/vendor/prettyplease/src/lit.rs new file mode 100644 index 00000000..10a86e4b --- /dev/null +++ b/vendor/prettyplease/src/lit.rs @@ -0,0 +1,57 @@ +use crate::algorithm::Printer; +use proc_macro2::Literal; +use syn::{Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr}; + +impl Printer { + pub fn lit(&mut self, lit: &Lit) { + match lit { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Lit::Str(lit) => self.lit_str(lit), + Lit::ByteStr(lit) => self.lit_byte_str(lit), + Lit::CStr(lit) => self.lit_c_str(lit), + Lit::Byte(lit) => self.lit_byte(lit), + Lit::Char(lit) => self.lit_char(lit), + Lit::Int(lit) => self.lit_int(lit), + Lit::Float(lit) => self.lit_float(lit), + Lit::Bool(lit) => self.lit_bool(lit), + Lit::Verbatim(lit) => self.lit_verbatim(lit), + _ => unimplemented!("unknown Lit"), + } + } + + pub fn lit_str(&mut self, lit: &LitStr) { + self.word(lit.token().to_string()); + } + + fn lit_byte_str(&mut self, lit: &LitByteStr) { + self.word(lit.token().to_string()); + } + + fn lit_c_str(&mut self, lit: &LitCStr) { + self.word(lit.token().to_string()); + } + + fn lit_byte(&mut self, lit: &LitByte) { + self.word(lit.token().to_string()); + } + + fn lit_char(&mut self, lit: &LitChar) { + self.word(lit.token().to_string()); + } + + fn lit_int(&mut self, lit: &LitInt) { + self.word(lit.token().to_string()); + } + + fn lit_float(&mut self, lit: &LitFloat) { + self.word(lit.token().to_string()); + } + + fn lit_bool(&mut self, lit: &LitBool) { + self.word(if lit.value { "true" } else { "false" }); + } + + fn lit_verbatim(&mut self, token: &Literal) { + self.word(token.to_string()); + } +} diff --git a/vendor/prettyplease/src/mac.rs b/vendor/prettyplease/src/mac.rs new file mode 100644 index 00000000..ddb2b5fe --- /dev/null +++ b/vendor/prettyplease/src/mac.rs @@ -0,0 +1,706 @@ +use crate::algorithm::Printer; +use crate::path::PathKind; +use crate::token::Token; +use crate::INDENT; +use proc_macro2::{Delimiter, Spacing, TokenStream}; +use syn::{Ident, Macro, MacroDelimiter}; + +impl Printer { + pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>, semicolon: bool) { + if mac.path.is_ident("macro_rules") { + if let Some(ident) = ident { + self.macro_rules(ident, &mac.tokens); + return; + } + } + #[cfg(feature = "verbatim")] + if ident.is_none() && self.standard_library_macro(mac, semicolon) { + return; + } + self.path(&mac.path, PathKind::Simple); + self.word("!"); + if let Some(ident) = ident { + self.nbsp(); + self.ident(ident); + } + let (open, close, delimiter_break) = match mac.delimiter { + MacroDelimiter::Paren(_) => ("(", ")", Self::zerobreak as fn(&mut Self)), + MacroDelimiter::Brace(_) => (" {", "}", Self::hardbreak as fn(&mut Self)), + MacroDelimiter::Bracket(_) => ("[", "]", Self::zerobreak as fn(&mut Self)), + }; + self.word(open); + if !mac.tokens.is_empty() { + self.cbox(INDENT); + delimiter_break(self); + self.ibox(0); + self.macro_rules_tokens(mac.tokens.clone(), false); + self.end(); + delimiter_break(self); + self.offset(-INDENT); + self.end(); + } + self.word(close); + if semicolon { + self.word(";"); + } + } + + fn macro_rules(&mut self, name: &Ident, rules: &TokenStream) { + enum State { + Start, + Matcher, + Equal, + Greater, + Expander, + } + + use State::*; + + self.word("macro_rules! "); + self.ident(name); + self.word(" {"); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + let mut state = State::Start; + for tt in rules.clone() { + let token = Token::from(tt); + match (state, token) { + (Start, Token::Group(delimiter, stream)) => { + self.delimiter_open(delimiter); + if !stream.is_empty() { + self.cbox(INDENT); + self.zerobreak(); + self.ibox(0); + self.macro_rules_tokens(stream, true); + self.end(); + self.zerobreak(); + self.offset(-INDENT); + self.end(); + } + self.delimiter_close(delimiter); + state = Matcher; + } + (Matcher, Token::Punct('=', Spacing::Joint)) => { + self.word(" ="); + state = Equal; + } + (Equal, Token::Punct('>', Spacing::Alone)) => { + self.word(">"); + state = Greater; + } + (Greater, Token::Group(_delimiter, stream)) => { + self.word(" {"); + self.neverbreak(); + if !stream.is_empty() { + self.cbox(INDENT); + self.hardbreak(); + self.ibox(0); + self.macro_rules_tokens(stream, false); + self.end(); + self.hardbreak(); + self.offset(-INDENT); + self.end(); + } + self.word("}"); + state = Expander; + } + (Expander, Token::Punct(';', Spacing::Alone)) => { + self.word(";"); + self.hardbreak(); + state = Start; + } + _ => unimplemented!("bad macro_rules syntax"), + } + } + match state { + Start => {} + Expander => { + self.word(";"); + self.hardbreak(); + } + _ => self.hardbreak(), + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + + pub fn macro_rules_tokens(&mut self, stream: TokenStream, matcher: bool) { + #[derive(PartialEq)] + enum State { + Start, + Dollar, + DollarCrate, + DollarIdent, + DollarIdentColon, + DollarParen, + DollarParenSep, + Pound, + PoundBang, + Dot, + Colon, + Colon2, + Ident, + IdentBang, + Delim, + Other, + } + + use State::*; + + let mut state = Start; + let mut previous_is_joint = true; + for tt in stream { + let token = Token::from(tt); + let (needs_space, next_state) = match (&state, &token) { + (Dollar, Token::Ident(_)) if matcher => (false, DollarIdent), + (Dollar, Token::Ident(ident)) if ident == "crate" => (false, DollarCrate), + (Dollar, Token::Ident(_)) => (false, Other), + (DollarIdent, Token::Punct(':', Spacing::Alone)) => (false, DollarIdentColon), + (DollarIdentColon, Token::Ident(_)) => (false, Other), + (DollarParen, Token::Punct('+' | '*' | '?', Spacing::Alone)) => (false, Other), + (DollarParen, Token::Ident(_) | Token::Literal(_)) => (false, DollarParenSep), + (DollarParen, Token::Punct(_, Spacing::Joint)) => (false, DollarParen), + (DollarParen, Token::Punct(_, Spacing::Alone)) => (false, DollarParenSep), + (DollarParenSep, Token::Punct('+' | '*', _)) => (false, Other), + (Pound, Token::Punct('!', _)) => (false, PoundBang), + (Dollar, Token::Group(Delimiter::Parenthesis, _)) => (false, DollarParen), + (Pound | PoundBang, Token::Group(Delimiter::Bracket, _)) => (false, Other), + (Ident, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { + (false, Delim) + } + (Ident, Token::Punct('!', Spacing::Alone)) => (false, IdentBang), + (IdentBang, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => { + (false, Other) + } + (Colon, Token::Punct(':', _)) => (false, Colon2), + (_, Token::Group(Delimiter::Parenthesis | Delimiter::Bracket, _)) => (true, Delim), + (_, Token::Group(Delimiter::Brace | Delimiter::None, _)) => (true, Other), + (_, Token::Ident(ident)) if !is_keyword(ident) => { + (state != Dot && state != Colon2, Ident) + } + (_, Token::Literal(lit)) if lit.to_string().ends_with('.') => (state != Dot, Other), + (_, Token::Literal(_)) => (state != Dot, Ident), + (_, Token::Punct(',' | ';', _)) => (false, Other), + (_, Token::Punct('.', _)) if !matcher => (state != Ident && state != Delim, Dot), + (_, Token::Punct(':', Spacing::Joint)) => { + (state != Ident && state != DollarCrate, Colon) + } + (_, Token::Punct('$', _)) => (true, Dollar), + (_, Token::Punct('#', _)) => (true, Pound), + (_, _) => (true, Other), + }; + if !previous_is_joint { + if needs_space { + self.space(); + } else if let Token::Punct('.', _) = token { + self.zerobreak(); + } + } + previous_is_joint = match token { + Token::Punct(_, Spacing::Joint) | Token::Punct('$', _) => true, + _ => false, + }; + self.single_token( + token, + if matcher { + |printer, stream| printer.macro_rules_tokens(stream, true) + } else { + |printer, stream| printer.macro_rules_tokens(stream, false) + }, + ); + state = next_state; + } + } +} + +pub(crate) fn requires_semi(delimiter: &MacroDelimiter) -> bool { + match delimiter { + MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => true, + MacroDelimiter::Brace(_) => false, + } +} + +fn is_keyword(ident: &Ident) -> bool { + match ident.to_string().as_str() { + "as" | "async" | "await" | "box" | "break" | "const" | "continue" | "crate" | "dyn" + | "else" | "enum" | "extern" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" + | "macro" | "match" | "mod" | "move" | "mut" | "pub" | "ref" | "return" | "static" + | "struct" | "trait" | "type" | "unsafe" | "use" | "where" | "while" | "yield" => true, + _ => false, + } +} + +#[cfg(feature = "verbatim")] +mod standard_library { + use crate::algorithm::Printer; + use crate::expr; + use crate::fixup::FixupContext; + use crate::iter::IterDelimited; + use crate::path::PathKind; + use crate::INDENT; + use syn::ext::IdentExt; + use syn::parse::{Parse, ParseStream, Parser, Result}; + use syn::punctuated::Punctuated; + use syn::{ + parenthesized, token, Attribute, Expr, ExprAssign, ExprPath, Ident, Lit, Macro, Pat, Path, + Token, Type, Visibility, + }; + + enum KnownMacro { + Expr(Expr), + Exprs(Vec), + Cfg(Cfg), + Matches(Matches), + ThreadLocal(Vec), + VecArray(Punctuated), + VecRepeat { elem: Expr, n: Expr }, + } + + enum Cfg { + Eq(Ident, Option), + Call(Ident, Vec), + } + + struct Matches { + expression: Expr, + pattern: Pat, + guard: Option, + } + + struct ThreadLocal { + attrs: Vec, + vis: Visibility, + name: Ident, + ty: Type, + init: Expr, + } + + struct FormatArgs { + format_string: Expr, + args: Vec, + } + + impl Parse for FormatArgs { + fn parse(input: ParseStream) -> Result { + let format_string: Expr = input.parse()?; + + let mut args = Vec::new(); + while !input.is_empty() { + input.parse::()?; + if input.is_empty() { + break; + } + let arg = if input.peek(Ident::peek_any) + && input.peek2(Token![=]) + && !input.peek2(Token![==]) + { + let key = input.call(Ident::parse_any)?; + let eq_token: Token![=] = input.parse()?; + let value: Expr = input.parse()?; + Expr::Assign(ExprAssign { + attrs: Vec::new(), + left: Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself: None, + path: Path::from(key), + })), + eq_token, + right: Box::new(value), + }) + } else { + input.parse()? + }; + args.push(arg); + } + + Ok(FormatArgs { + format_string, + args, + }) + } + } + + impl KnownMacro { + fn parse_expr(input: ParseStream) -> Result { + let expr: Expr = input.parse()?; + Ok(KnownMacro::Expr(expr)) + } + + fn parse_expr_comma(input: ParseStream) -> Result { + let expr: Expr = input.parse()?; + input.parse::>()?; + Ok(KnownMacro::Exprs(vec![expr])) + } + + fn parse_exprs(input: ParseStream) -> Result { + let exprs = input.parse_terminated(Expr::parse, Token![,])?; + Ok(KnownMacro::Exprs(Vec::from_iter(exprs))) + } + + fn parse_assert(input: ParseStream) -> Result { + let mut exprs = Vec::new(); + let cond: Expr = input.parse()?; + exprs.push(cond); + if input.parse::>()?.is_some() && !input.is_empty() { + let format_args: FormatArgs = input.parse()?; + exprs.push(format_args.format_string); + exprs.extend(format_args.args); + } + Ok(KnownMacro::Exprs(exprs)) + } + + fn parse_assert_cmp(input: ParseStream) -> Result { + let mut exprs = Vec::new(); + let left: Expr = input.parse()?; + exprs.push(left); + input.parse::()?; + let right: Expr = input.parse()?; + exprs.push(right); + if input.parse::>()?.is_some() && !input.is_empty() { + let format_args: FormatArgs = input.parse()?; + exprs.push(format_args.format_string); + exprs.extend(format_args.args); + } + Ok(KnownMacro::Exprs(exprs)) + } + + fn parse_cfg(input: ParseStream) -> Result { + fn parse_single(input: ParseStream) -> Result { + let ident: Ident = input.parse()?; + if input.peek(token::Paren) && (ident == "all" || ident == "any") { + let content; + parenthesized!(content in input); + let list = content.call(parse_multiple)?; + Ok(Cfg::Call(ident, list)) + } else if input.peek(token::Paren) && ident == "not" { + let content; + parenthesized!(content in input); + let cfg = content.call(parse_single)?; + content.parse::>()?; + Ok(Cfg::Call(ident, vec![cfg])) + } else if input.peek(Token![=]) { + input.parse::()?; + let string: Lit = input.parse()?; + Ok(Cfg::Eq(ident, Some(string))) + } else { + Ok(Cfg::Eq(ident, None)) + } + } + + fn parse_multiple(input: ParseStream) -> Result> { + let mut vec = Vec::new(); + while !input.is_empty() { + let cfg = input.call(parse_single)?; + vec.push(cfg); + if input.is_empty() { + break; + } + input.parse::()?; + } + Ok(vec) + } + + let cfg = input.call(parse_single)?; + input.parse::>()?; + Ok(KnownMacro::Cfg(cfg)) + } + + fn parse_env(input: ParseStream) -> Result { + let mut exprs = Vec::new(); + let name: Expr = input.parse()?; + exprs.push(name); + if input.parse::>()?.is_some() && !input.is_empty() { + let error_msg: Expr = input.parse()?; + exprs.push(error_msg); + input.parse::>()?; + } + Ok(KnownMacro::Exprs(exprs)) + } + + fn parse_format_args(input: ParseStream) -> Result { + let format_args: FormatArgs = input.parse()?; + let mut exprs = format_args.args; + exprs.insert(0, format_args.format_string); + Ok(KnownMacro::Exprs(exprs)) + } + + fn parse_matches(input: ParseStream) -> Result { + let expression: Expr = input.parse()?; + input.parse::()?; + let pattern = input.call(Pat::parse_multi_with_leading_vert)?; + let guard = if input.parse::>()?.is_some() { + Some(input.parse()?) + } else { + None + }; + input.parse::>()?; + Ok(KnownMacro::Matches(Matches { + expression, + pattern, + guard, + })) + } + + fn parse_thread_local(input: ParseStream) -> Result { + let mut items = Vec::new(); + while !input.is_empty() { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + input.parse::()?; + let name: Ident = input.parse()?; + input.parse::()?; + let ty: Type = input.parse()?; + input.parse::()?; + let init: Expr = input.parse()?; + if input.is_empty() { + break; + } + input.parse::()?; + items.push(ThreadLocal { + attrs, + vis, + name, + ty, + init, + }); + } + Ok(KnownMacro::ThreadLocal(items)) + } + + fn parse_vec(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(KnownMacro::VecArray(Punctuated::new())); + } + let first: Expr = input.parse()?; + if input.parse::>()?.is_some() { + let len: Expr = input.parse()?; + Ok(KnownMacro::VecRepeat { + elem: first, + n: len, + }) + } else { + let mut vec = Punctuated::new(); + vec.push_value(first); + while !input.is_empty() { + let comma: Token![,] = input.parse()?; + vec.push_punct(comma); + if input.is_empty() { + break; + } + let next: Expr = input.parse()?; + vec.push_value(next); + } + Ok(KnownMacro::VecArray(vec)) + } + } + + fn parse_write(input: ParseStream) -> Result { + let mut exprs = Vec::new(); + let dst: Expr = input.parse()?; + exprs.push(dst); + input.parse::()?; + let format_args: FormatArgs = input.parse()?; + exprs.push(format_args.format_string); + exprs.extend(format_args.args); + Ok(KnownMacro::Exprs(exprs)) + } + + fn parse_writeln(input: ParseStream) -> Result { + let mut exprs = Vec::new(); + let dst: Expr = input.parse()?; + exprs.push(dst); + if input.parse::>()?.is_some() && !input.is_empty() { + let format_args: FormatArgs = input.parse()?; + exprs.push(format_args.format_string); + exprs.extend(format_args.args); + } + Ok(KnownMacro::Exprs(exprs)) + } + } + + impl Printer { + pub fn standard_library_macro(&mut self, mac: &Macro, mut semicolon: bool) -> bool { + let name = mac.path.segments.last().unwrap().ident.to_string(); + let parser = match name.as_str() { + "addr_of" | "addr_of_mut" => KnownMacro::parse_expr, + "assert" | "debug_assert" => KnownMacro::parse_assert, + "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne" => { + KnownMacro::parse_assert_cmp + } + "cfg" => KnownMacro::parse_cfg, + "compile_error" | "include" | "include_bytes" | "include_str" | "option_env" => { + KnownMacro::parse_expr_comma + } + "concat" | "concat_bytes" | "dbg" => KnownMacro::parse_exprs, + "const_format_args" | "eprint" | "eprintln" | "format" | "format_args" + | "format_args_nl" | "panic" | "print" | "println" | "todo" | "unimplemented" + | "unreachable" => KnownMacro::parse_format_args, + "env" => KnownMacro::parse_env, + "matches" => KnownMacro::parse_matches, + "thread_local" => KnownMacro::parse_thread_local, + "vec" => KnownMacro::parse_vec, + "write" => KnownMacro::parse_write, + "writeln" => KnownMacro::parse_writeln, + _ => return false, + }; + + let known_macro = match parser.parse2(mac.tokens.clone()) { + Ok(known_macro) => known_macro, + Err(_) => return false, + }; + + self.path(&mac.path, PathKind::Simple); + self.word("!"); + + match &known_macro { + KnownMacro::Expr(expr) => { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + self.expr(expr, FixupContext::NONE); + self.zerobreak(); + self.offset(-INDENT); + self.end(); + self.word(")"); + } + KnownMacro::Exprs(exprs) => { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for elem in exprs.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + self.trailing_comma(elem.is_last); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + KnownMacro::Cfg(cfg) => { + self.word("("); + self.cfg(cfg); + self.word(")"); + } + KnownMacro::Matches(matches) => { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + self.expr(&matches.expression, FixupContext::NONE); + self.word(","); + self.space(); + self.pat(&matches.pattern); + if let Some(guard) = &matches.guard { + self.space(); + self.word("if "); + self.expr(guard, FixupContext::NONE); + } + self.zerobreak(); + self.offset(-INDENT); + self.end(); + self.word(")"); + } + KnownMacro::ThreadLocal(items) => { + self.word(" {"); + self.cbox(INDENT); + self.hardbreak_if_nonempty(); + for item in items { + self.outer_attrs(&item.attrs); + self.cbox(0); + self.visibility(&item.vis); + self.word("static "); + self.ident(&item.name); + self.word(": "); + self.ty(&item.ty); + self.word(" = "); + self.neverbreak(); + self.expr(&item.init, FixupContext::NONE); + self.word(";"); + self.end(); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + semicolon = false; + } + KnownMacro::VecArray(vec) => { + if vec.is_empty() { + self.word("[]"); + } else if expr::simple_array(vec) { + self.cbox(INDENT); + self.word("["); + self.zerobreak(); + self.ibox(0); + for elem in vec.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + if !elem.is_last { + self.word(","); + self.space(); + } + } + self.end(); + self.trailing_comma(true); + self.offset(-INDENT); + self.word("]"); + self.end(); + } else { + self.word("["); + self.cbox(INDENT); + self.zerobreak(); + for elem in vec.iter().delimited() { + self.expr(&elem, FixupContext::NONE); + self.trailing_comma(elem.is_last); + } + self.offset(-INDENT); + self.end(); + self.word("]"); + } + } + KnownMacro::VecRepeat { elem, n } => { + self.word("["); + self.cbox(INDENT); + self.zerobreak(); + self.expr(elem, FixupContext::NONE); + self.word(";"); + self.space(); + self.expr(n, FixupContext::NONE); + self.zerobreak(); + self.offset(-INDENT); + self.end(); + self.word("]"); + } + } + + if semicolon { + self.word(";"); + } + + true + } + + fn cfg(&mut self, cfg: &Cfg) { + match cfg { + Cfg::Eq(ident, value) => { + self.ident(ident); + if let Some(value) = value { + self.word(" = "); + self.lit(value); + } + } + Cfg::Call(ident, args) => { + self.ident(ident); + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for arg in args.iter().delimited() { + self.cfg(&arg); + self.trailing_comma(arg.is_last); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + } + } + } +} diff --git a/vendor/prettyplease/src/pat.rs b/vendor/prettyplease/src/pat.rs new file mode 100644 index 00000000..23a38cbb --- /dev/null +++ b/vendor/prettyplease/src/pat.rs @@ -0,0 +1,254 @@ +use crate::algorithm::Printer; +use crate::fixup::FixupContext; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::TokenStream; +use syn::{ + FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple, + PatTupleStruct, PatType, PatWild, +}; + +impl Printer { + pub fn pat(&mut self, pat: &Pat) { + match pat { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Pat::Const(pat) => self.expr_const(pat), + Pat::Ident(pat) => self.pat_ident(pat), + Pat::Lit(pat) => self.expr_lit(pat), + Pat::Macro(pat) => self.expr_macro(pat), + Pat::Or(pat) => self.pat_or(pat), + Pat::Paren(pat) => self.pat_paren(pat), + Pat::Path(pat) => self.expr_path(pat), + Pat::Range(pat) => self.expr_range(pat, FixupContext::NONE), + Pat::Reference(pat) => self.pat_reference(pat), + Pat::Rest(pat) => self.pat_rest(pat), + Pat::Slice(pat) => self.pat_slice(pat), + Pat::Struct(pat) => self.pat_struct(pat), + Pat::Tuple(pat) => self.pat_tuple(pat), + Pat::TupleStruct(pat) => self.pat_tuple_struct(pat), + Pat::Type(pat) => self.pat_type(pat), + Pat::Verbatim(pat) => self.pat_verbatim(pat), + Pat::Wild(pat) => self.pat_wild(pat), + _ => unimplemented!("unknown Pat"), + } + } + + fn pat_ident(&mut self, pat: &PatIdent) { + self.outer_attrs(&pat.attrs); + if pat.by_ref.is_some() { + self.word("ref "); + } + if pat.mutability.is_some() { + self.word("mut "); + } + self.ident(&pat.ident); + if let Some((_at_token, subpat)) = &pat.subpat { + self.word(" @ "); + self.pat(subpat); + } + } + + fn pat_or(&mut self, pat: &PatOr) { + self.outer_attrs(&pat.attrs); + let mut consistent_break = false; + for case in &pat.cases { + match case { + Pat::Lit(_) | Pat::Wild(_) => {} + _ => { + consistent_break = true; + break; + } + } + } + if consistent_break { + self.cbox(0); + } else { + self.ibox(0); + } + for case in pat.cases.iter().delimited() { + if !case.is_first { + self.space(); + self.word("| "); + } + self.pat(&case); + } + self.end(); + } + + fn pat_paren(&mut self, pat: &PatParen) { + self.outer_attrs(&pat.attrs); + self.word("("); + self.pat(&pat.pat); + self.word(")"); + } + + fn pat_reference(&mut self, pat: &PatReference) { + self.outer_attrs(&pat.attrs); + self.word("&"); + if pat.mutability.is_some() { + self.word("mut "); + } + self.pat(&pat.pat); + } + + fn pat_rest(&mut self, pat: &PatRest) { + self.outer_attrs(&pat.attrs); + self.word(".."); + } + + fn pat_slice(&mut self, pat: &PatSlice) { + self.outer_attrs(&pat.attrs); + self.word("["); + for elem in pat.elems.iter().delimited() { + self.pat(&elem); + self.trailing_comma(elem.is_last); + } + self.word("]"); + } + + fn pat_struct(&mut self, pat: &PatStruct) { + self.outer_attrs(&pat.attrs); + self.cbox(INDENT); + self.path(&pat.path, PathKind::Expr); + self.word(" {"); + self.space_if_nonempty(); + for field in pat.fields.iter().delimited() { + self.field_pat(&field); + self.trailing_comma_or_space(field.is_last && pat.rest.is_none()); + } + if let Some(rest) = &pat.rest { + self.pat_rest(rest); + self.space(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + + fn pat_tuple(&mut self, pat: &PatTuple) { + self.outer_attrs(&pat.attrs); + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for elem in pat.elems.iter().delimited() { + self.pat(&elem); + if pat.elems.len() == 1 { + if pat.elems.trailing_punct() { + self.word(","); + } + self.zerobreak(); + } else { + self.trailing_comma(elem.is_last); + } + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + + fn pat_tuple_struct(&mut self, pat: &PatTupleStruct) { + self.outer_attrs(&pat.attrs); + self.path(&pat.path, PathKind::Expr); + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for elem in pat.elems.iter().delimited() { + self.pat(&elem); + self.trailing_comma(elem.is_last); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + + pub fn pat_type(&mut self, pat: &PatType) { + self.outer_attrs(&pat.attrs); + self.pat(&pat.pat); + self.word(": "); + self.ty(&pat.ty); + } + + #[cfg(not(feature = "verbatim"))] + fn pat_verbatim(&mut self, pat: &TokenStream) { + unimplemented!("Pat::Verbatim `{}`", pat); + } + + #[cfg(feature = "verbatim")] + fn pat_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::{braced, Attribute, Block, Token}; + + enum PatVerbatim { + Ellipsis, + Box(Pat), + Const(PatConst), + } + + struct PatConst { + attrs: Vec, + block: Block, + } + + impl Parse for PatVerbatim { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![box]) { + input.parse::()?; + let inner = Pat::parse_single(input)?; + Ok(PatVerbatim::Box(inner)) + } else if lookahead.peek(Token![const]) { + input.parse::()?; + let content; + let brace_token = braced!(content in input); + let attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + Ok(PatVerbatim::Const(PatConst { + attrs, + block: Block { brace_token, stmts }, + })) + } else if lookahead.peek(Token![...]) { + input.parse::()?; + Ok(PatVerbatim::Ellipsis) + } else { + Err(lookahead.error()) + } + } + } + + let pat: PatVerbatim = match syn::parse2(tokens.clone()) { + Ok(pat) => pat, + Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens), + }; + + match pat { + PatVerbatim::Ellipsis => { + self.word("..."); + } + PatVerbatim::Box(pat) => { + self.word("box "); + self.pat(&pat); + } + PatVerbatim::Const(pat) => { + self.word("const "); + self.cbox(INDENT); + self.small_block(&pat.block, &pat.attrs); + self.end(); + } + } + } + + fn pat_wild(&mut self, pat: &PatWild) { + self.outer_attrs(&pat.attrs); + self.word("_"); + } + + fn field_pat(&mut self, field_pat: &FieldPat) { + self.outer_attrs(&field_pat.attrs); + if field_pat.colon_token.is_some() { + self.member(&field_pat.member); + self.word(": "); + } + self.pat(&field_pat.pat); + } +} diff --git a/vendor/prettyplease/src/path.rs b/vendor/prettyplease/src/path.rs new file mode 100644 index 00000000..44428cc6 --- /dev/null +++ b/vendor/prettyplease/src/path.rs @@ -0,0 +1,194 @@ +use crate::algorithm::Printer; +use crate::iter::IterDelimited; +use crate::INDENT; +use std::ptr; +use syn::{ + AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument, + ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, +}; + +#[derive(Copy, Clone, PartialEq)] +pub enum PathKind { + // a::B + Simple, + // a::B + Type, + // a::B:: + Expr, +} + +impl Printer { + pub fn path(&mut self, path: &Path, kind: PathKind) { + assert!(!path.segments.is_empty()); + for segment in path.segments.iter().delimited() { + if !segment.is_first || path.leading_colon.is_some() { + self.word("::"); + } + self.path_segment(&segment, kind); + } + } + + pub fn path_segment(&mut self, segment: &PathSegment, kind: PathKind) { + self.ident(&segment.ident); + self.path_arguments(&segment.arguments, kind); + } + + fn path_arguments(&mut self, arguments: &PathArguments, kind: PathKind) { + match arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(arguments) => { + self.angle_bracketed_generic_arguments(arguments, kind); + } + PathArguments::Parenthesized(arguments) => { + self.parenthesized_generic_arguments(arguments); + } + } + } + + fn generic_argument(&mut self, arg: &GenericArgument) { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime), + GenericArgument::Type(ty) => self.ty(ty), + GenericArgument::Const(expr) => self.const_argument(expr), + GenericArgument::AssocType(assoc) => self.assoc_type(assoc), + GenericArgument::AssocConst(assoc) => self.assoc_const(assoc), + GenericArgument::Constraint(constraint) => self.constraint(constraint), + _ => unimplemented!("unknown GenericArgument"), + } + } + + pub fn angle_bracketed_generic_arguments( + &mut self, + generic: &AngleBracketedGenericArguments, + path_kind: PathKind, + ) { + if generic.args.is_empty() || path_kind == PathKind::Simple { + return; + } + + if path_kind == PathKind::Expr { + self.word("::"); + } + self.word("<"); + self.cbox(INDENT); + self.zerobreak(); + + // Print lifetimes before types/consts/bindings, regardless of their + // order in self.args. + #[derive(Ord, PartialOrd, Eq, PartialEq)] + enum Group { + First, + Second, + } + fn group(arg: &GenericArgument) -> Group { + match arg { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + GenericArgument::Lifetime(_) => Group::First, + GenericArgument::Type(_) + | GenericArgument::Const(_) + | GenericArgument::AssocType(_) + | GenericArgument::AssocConst(_) + | GenericArgument::Constraint(_) => Group::Second, + _ => Group::Second, + } + } + let last = generic.args.iter().max_by_key(|param| group(param)); + for current_group in [Group::First, Group::Second] { + for arg in &generic.args { + if group(arg) == current_group { + self.generic_argument(arg); + self.trailing_comma(ptr::eq(arg, last.unwrap())); + } + } + } + + self.offset(-INDENT); + self.end(); + self.word(">"); + } + + fn assoc_type(&mut self, assoc: &AssocType) { + self.ident(&assoc.ident); + if let Some(generics) = &assoc.generics { + self.angle_bracketed_generic_arguments(generics, PathKind::Type); + } + self.word(" = "); + self.ty(&assoc.ty); + } + + fn assoc_const(&mut self, assoc: &AssocConst) { + self.ident(&assoc.ident); + if let Some(generics) = &assoc.generics { + self.angle_bracketed_generic_arguments(generics, PathKind::Type); + } + self.word(" = "); + self.const_argument(&assoc.value); + } + + fn constraint(&mut self, constraint: &Constraint) { + self.ident(&constraint.ident); + if let Some(generics) = &constraint.generics { + self.angle_bracketed_generic_arguments(generics, PathKind::Type); + } + self.ibox(INDENT); + for bound in constraint.bounds.iter().delimited() { + if bound.is_first { + self.word(": "); + } else { + self.space(); + self.word("+ "); + } + self.type_param_bound(&bound); + } + self.end(); + } + + fn parenthesized_generic_arguments(&mut self, arguments: &ParenthesizedGenericArguments) { + self.cbox(INDENT); + self.word("("); + self.zerobreak(); + for ty in arguments.inputs.iter().delimited() { + self.ty(&ty); + self.trailing_comma(ty.is_last); + } + self.offset(-INDENT); + self.word(")"); + self.return_type(&arguments.output); + self.end(); + } + + pub fn qpath(&mut self, qself: &Option, path: &Path, kind: PathKind) { + let qself = if let Some(qself) = qself { + qself + } else { + self.path(path, kind); + return; + }; + + assert!(qself.position < path.segments.len()); + + self.word("<"); + self.ty(&qself.ty); + + let mut segments = path.segments.iter(); + if qself.position > 0 { + self.word(" as "); + for segment in segments.by_ref().take(qself.position).delimited() { + if !segment.is_first || path.leading_colon.is_some() { + self.word("::"); + } + self.path_segment(&segment, PathKind::Type); + if segment.is_last { + self.word(">"); + } + } + } else { + self.word(">"); + } + for segment in segments { + self.word("::"); + self.path_segment(segment, kind); + } + } +} diff --git a/vendor/prettyplease/src/precedence.rs b/vendor/prettyplease/src/precedence.rs new file mode 100644 index 00000000..03117d56 --- /dev/null +++ b/vendor/prettyplease/src/precedence.rs @@ -0,0 +1,148 @@ +use syn::{ + AttrStyle, Attribute, BinOp, Expr, ExprArray, ExprAsync, ExprAwait, ExprBlock, ExprBreak, + ExprCall, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprInfer, + ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, + ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnsafe, ExprWhile, ExprYield, + ReturnType, +}; + +// Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence +#[derive(Copy, Clone, PartialEq, PartialOrd)] +pub enum Precedence { + // return, break, closures + Jump, + // = += -= *= /= %= &= |= ^= <<= >>= + Assign, + // .. ..= + Range, + // || + Or, + // && + And, + // let + Let, + // == != < > <= >= + Compare, + // | + BitOr, + // ^ + BitXor, + // & + BitAnd, + // << >> + Shift, + // + - + Sum, + // * / % + Product, + // as + Cast, + // unary - * ! & &mut + Prefix, + // paths, loops, function calls, array indexing, field expressions, method calls + Unambiguous, +} + +impl Precedence { + pub(crate) const MIN: Self = Precedence::Jump; + + pub(crate) fn of_binop(op: &BinOp) -> Self { + match op { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum, + BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product, + BinOp::And(_) => Precedence::And, + BinOp::Or(_) => Precedence::Or, + BinOp::BitXor(_) => Precedence::BitXor, + BinOp::BitAnd(_) => Precedence::BitAnd, + BinOp::BitOr(_) => Precedence::BitOr, + BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift, + + BinOp::Eq(_) + | BinOp::Lt(_) + | BinOp::Le(_) + | BinOp::Ne(_) + | BinOp::Ge(_) + | BinOp::Gt(_) => Precedence::Compare, + + BinOp::AddAssign(_) + | BinOp::SubAssign(_) + | BinOp::MulAssign(_) + | BinOp::DivAssign(_) + | BinOp::RemAssign(_) + | BinOp::BitXorAssign(_) + | BinOp::BitAndAssign(_) + | BinOp::BitOrAssign(_) + | BinOp::ShlAssign(_) + | BinOp::ShrAssign(_) => Precedence::Assign, + + _ => Precedence::MIN, + } + } + + pub(crate) fn of(e: &Expr) -> Self { + fn prefix_attrs(attrs: &[Attribute]) -> Precedence { + for attr in attrs { + if let AttrStyle::Outer = attr.style { + return Precedence::Prefix; + } + } + Precedence::Unambiguous + } + + match e { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Closure(e) => match e.output { + ReturnType::Default => Precedence::Jump, + ReturnType::Type(..) => prefix_attrs(&e.attrs), + }, + + Expr::Break(ExprBreak { expr, .. }) + | Expr::Return(ExprReturn { expr, .. }) + | Expr::Yield(ExprYield { expr, .. }) => match expr { + Some(_) => Precedence::Jump, + None => Precedence::Unambiguous, + }, + + Expr::Assign(_) => Precedence::Assign, + Expr::Range(_) => Precedence::Range, + Expr::Binary(e) => Precedence::of_binop(&e.op), + Expr::Let(_) => Precedence::Let, + Expr::Cast(_) => Precedence::Cast, + Expr::RawAddr(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, + + Expr::Array(ExprArray { attrs, .. }) + | Expr::Async(ExprAsync { attrs, .. }) + | Expr::Await(ExprAwait { attrs, .. }) + | Expr::Block(ExprBlock { attrs, .. }) + | Expr::Call(ExprCall { attrs, .. }) + | Expr::Const(ExprConst { attrs, .. }) + | Expr::Continue(ExprContinue { attrs, .. }) + | Expr::Field(ExprField { attrs, .. }) + | Expr::ForLoop(ExprForLoop { attrs, .. }) + | Expr::If(ExprIf { attrs, .. }) + | Expr::Index(ExprIndex { attrs, .. }) + | Expr::Infer(ExprInfer { attrs, .. }) + | Expr::Lit(ExprLit { attrs, .. }) + | Expr::Loop(ExprLoop { attrs, .. }) + | Expr::Macro(ExprMacro { attrs, .. }) + | Expr::Match(ExprMatch { attrs, .. }) + | Expr::MethodCall(ExprMethodCall { attrs, .. }) + | Expr::Paren(ExprParen { attrs, .. }) + | Expr::Path(ExprPath { attrs, .. }) + | Expr::Repeat(ExprRepeat { attrs, .. }) + | Expr::Struct(ExprStruct { attrs, .. }) + | Expr::Try(ExprTry { attrs, .. }) + | Expr::TryBlock(ExprTryBlock { attrs, .. }) + | Expr::Tuple(ExprTuple { attrs, .. }) + | Expr::Unsafe(ExprUnsafe { attrs, .. }) + | Expr::While(ExprWhile { attrs, .. }) => prefix_attrs(attrs), + + Expr::Group(e) => Precedence::of(&e.expr), + + Expr::Verbatim(_) => Precedence::Unambiguous, + + _ => Precedence::Unambiguous, + } + } +} diff --git a/vendor/prettyplease/src/ring.rs b/vendor/prettyplease/src/ring.rs new file mode 100644 index 00000000..882a988e --- /dev/null +++ b/vendor/prettyplease/src/ring.rs @@ -0,0 +1,81 @@ +use std::collections::VecDeque; +use std::ops::{Index, IndexMut, Range}; + +pub struct RingBuffer { + data: VecDeque, + // Abstract index of data[0] in infinitely sized queue + offset: usize, +} + +impl RingBuffer { + pub fn new() -> Self { + RingBuffer { + data: VecDeque::new(), + offset: 0, + } + } + + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn len(&self) -> usize { + self.data.len() + } + + pub fn push(&mut self, value: T) -> usize { + let index = self.offset + self.data.len(); + self.data.push_back(value); + index + } + + pub fn clear(&mut self) { + self.data.clear(); + } + + pub fn index_range(&self) -> Range { + self.offset..self.offset + self.data.len() + } + + pub fn first(&self) -> &T { + &self.data[0] + } + + pub fn first_mut(&mut self) -> &mut T { + &mut self.data[0] + } + + pub fn pop_first(&mut self) -> T { + self.offset += 1; + self.data.pop_front().unwrap() + } + + pub fn last(&self) -> &T { + self.data.back().unwrap() + } + + pub fn last_mut(&mut self) -> &mut T { + self.data.back_mut().unwrap() + } + + pub fn second_last(&self) -> &T { + &self.data[self.data.len() - 2] + } + + pub fn pop_last(&mut self) { + self.data.pop_back().unwrap(); + } +} + +impl Index for RingBuffer { + type Output = T; + fn index(&self, index: usize) -> &Self::Output { + &self.data[index.checked_sub(self.offset).unwrap()] + } +} + +impl IndexMut for RingBuffer { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.data[index.checked_sub(self.offset).unwrap()] + } +} diff --git a/vendor/prettyplease/src/stmt.rs b/vendor/prettyplease/src/stmt.rs new file mode 100644 index 00000000..ce58200e --- /dev/null +++ b/vendor/prettyplease/src/stmt.rs @@ -0,0 +1,221 @@ +use crate::algorithm::Printer; +use crate::classify; +use crate::expr; +use crate::fixup::FixupContext; +use crate::mac; +use crate::INDENT; +use syn::{BinOp, Expr, Stmt}; + +impl Printer { + pub fn stmt(&mut self, stmt: &Stmt, is_last: bool) { + match stmt { + Stmt::Local(local) => { + self.outer_attrs(&local.attrs); + self.ibox(0); + self.word("let "); + self.pat(&local.pat); + if let Some(local_init) = &local.init { + self.word(" = "); + self.neverbreak(); + self.subexpr( + &local_init.expr, + local_init.diverge.is_some() + && classify::expr_trailing_brace(&local_init.expr), + FixupContext::NONE, + ); + if let Some((_else, diverge)) = &local_init.diverge { + self.space(); + self.word("else "); + self.end(); + self.neverbreak(); + self.cbox(INDENT); + if let Some(expr) = expr::simple_block(diverge) { + self.small_block(&expr.block, &[]); + } else { + self.expr_as_small_block(diverge, INDENT); + } + } + } + self.end(); + self.word(";"); + self.hardbreak(); + } + Stmt::Item(item) => self.item(item), + Stmt::Expr(expr, None) => { + if break_after(expr) { + self.ibox(0); + self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt()); + if add_semi(expr) { + self.word(";"); + } + self.end(); + self.hardbreak(); + } else { + self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt()); + } + } + Stmt::Expr(expr, Some(_semi)) => { + if let Expr::Verbatim(tokens) = expr { + if tokens.is_empty() { + return; + } + } + self.ibox(0); + self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt()); + if !remove_semi(expr) { + self.word(";"); + } + self.end(); + self.hardbreak(); + } + Stmt::Macro(stmt) => { + self.outer_attrs(&stmt.attrs); + let semicolon = stmt.semi_token.is_some() + || !is_last && mac::requires_semi(&stmt.mac.delimiter); + self.mac(&stmt.mac, None, semicolon); + self.hardbreak(); + } + } + } +} + +pub fn add_semi(expr: &Expr) -> bool { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => { + true + } + Expr::Binary(expr) => + { + match expr.op { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + BinOp::AddAssign(_) + | BinOp::SubAssign(_) + | BinOp::MulAssign(_) + | BinOp::DivAssign(_) + | BinOp::RemAssign(_) + | BinOp::BitXorAssign(_) + | BinOp::BitAndAssign(_) + | BinOp::BitOrAssign(_) + | BinOp::ShlAssign(_) + | BinOp::ShrAssign(_) => true, + BinOp::Add(_) + | BinOp::Sub(_) + | BinOp::Mul(_) + | BinOp::Div(_) + | BinOp::Rem(_) + | BinOp::And(_) + | BinOp::Or(_) + | BinOp::BitXor(_) + | BinOp::BitAnd(_) + | BinOp::BitOr(_) + | BinOp::Shl(_) + | BinOp::Shr(_) + | BinOp::Eq(_) + | BinOp::Lt(_) + | BinOp::Le(_) + | BinOp::Ne(_) + | BinOp::Ge(_) + | BinOp::Gt(_) => false, + _ => unimplemented!("unknown BinOp"), + } + } + Expr::Group(group) => add_semi(&group.expr), + + Expr::Array(_) + | Expr::Async(_) + | Expr::Await(_) + | Expr::Block(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Field(_) + | Expr::ForLoop(_) + | Expr::If(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Struct(_) + | Expr::Try(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::While(_) => false, + + _ => false, + } +} + +pub fn break_after(expr: &Expr) -> bool { + if let Expr::Group(group) = expr { + if let Expr::Verbatim(verbatim) = group.expr.as_ref() { + return !verbatim.is_empty(); + } + } + true +} + +fn remove_semi(expr: &Expr) -> bool { + match expr { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Expr::ForLoop(_) | Expr::While(_) => true, + Expr::Group(group) => remove_semi(&group.expr), + Expr::If(expr) => match &expr.else_branch { + Some((_else_token, else_branch)) => remove_semi(else_branch), + None => true, + }, + + Expr::Array(_) + | Expr::Assign(_) + | Expr::Async(_) + | Expr::Await(_) + | Expr::Binary(_) + | Expr::Block(_) + | Expr::Break(_) + | Expr::Call(_) + | Expr::Cast(_) + | Expr::Closure(_) + | Expr::Continue(_) + | Expr::Const(_) + | Expr::Field(_) + | Expr::Index(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Loop(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::MethodCall(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Range(_) + | Expr::RawAddr(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::Try(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::Yield(_) => false, + + _ => false, + } +} diff --git a/vendor/prettyplease/src/token.rs b/vendor/prettyplease/src/token.rs new file mode 100644 index 00000000..e41fd728 --- /dev/null +++ b/vendor/prettyplease/src/token.rs @@ -0,0 +1,80 @@ +use crate::algorithm::Printer; +use proc_macro2::{Delimiter, Ident, Literal, Spacing, TokenStream, TokenTree}; + +impl Printer { + pub fn single_token(&mut self, token: Token, group_contents: fn(&mut Self, TokenStream)) { + match token { + Token::Group(delimiter, stream) => self.token_group(delimiter, stream, group_contents), + Token::Ident(ident) => self.ident(&ident), + Token::Punct(ch, _spacing) => self.token_punct(ch), + Token::Literal(literal) => self.token_literal(&literal), + } + } + + fn token_group( + &mut self, + delimiter: Delimiter, + stream: TokenStream, + group_contents: fn(&mut Self, TokenStream), + ) { + self.delimiter_open(delimiter); + if !stream.is_empty() { + if delimiter == Delimiter::Brace { + self.space(); + } + group_contents(self, stream); + if delimiter == Delimiter::Brace { + self.space(); + } + } + self.delimiter_close(delimiter); + } + + pub fn ident(&mut self, ident: &Ident) { + self.word(ident.to_string()); + } + + pub fn token_punct(&mut self, ch: char) { + self.word(ch.to_string()); + } + + pub fn token_literal(&mut self, literal: &Literal) { + self.word(literal.to_string()); + } + + pub fn delimiter_open(&mut self, delimiter: Delimiter) { + self.word(match delimiter { + Delimiter::Parenthesis => "(", + Delimiter::Brace => "{", + Delimiter::Bracket => "[", + Delimiter::None => return, + }); + } + + pub fn delimiter_close(&mut self, delimiter: Delimiter) { + self.word(match delimiter { + Delimiter::Parenthesis => ")", + Delimiter::Brace => "}", + Delimiter::Bracket => "]", + Delimiter::None => return, + }); + } +} + +pub enum Token { + Group(Delimiter, TokenStream), + Ident(Ident), + Punct(char, Spacing), + Literal(Literal), +} + +impl From for Token { + fn from(tt: TokenTree) -> Self { + match tt { + TokenTree::Group(group) => Token::Group(group.delimiter(), group.stream()), + TokenTree::Ident(ident) => Token::Ident(ident), + TokenTree::Punct(punct) => Token::Punct(punct.as_char(), punct.spacing()), + TokenTree::Literal(literal) => Token::Literal(literal), + } + } +} diff --git a/vendor/prettyplease/src/ty.rs b/vendor/prettyplease/src/ty.rs new file mode 100644 index 00000000..7f92821a --- /dev/null +++ b/vendor/prettyplease/src/ty.rs @@ -0,0 +1,339 @@ +use crate::algorithm::Printer; +use crate::fixup::FixupContext; +use crate::iter::IterDelimited; +use crate::path::PathKind; +use crate::INDENT; +use proc_macro2::TokenStream; +use syn::{ + Abi, BareFnArg, BareVariadic, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, + TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, + TypeSlice, TypeTraitObject, TypeTuple, +}; + +impl Printer { + pub fn ty(&mut self, ty: &Type) { + match ty { + #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + Type::Array(ty) => self.type_array(ty), + Type::BareFn(ty) => self.type_bare_fn(ty), + Type::Group(ty) => self.type_group(ty), + Type::ImplTrait(ty) => self.type_impl_trait(ty), + Type::Infer(ty) => self.type_infer(ty), + Type::Macro(ty) => self.type_macro(ty), + Type::Never(ty) => self.type_never(ty), + Type::Paren(ty) => self.type_paren(ty), + Type::Path(ty) => self.type_path(ty), + Type::Ptr(ty) => self.type_ptr(ty), + Type::Reference(ty) => self.type_reference(ty), + Type::Slice(ty) => self.type_slice(ty), + Type::TraitObject(ty) => self.type_trait_object(ty), + Type::Tuple(ty) => self.type_tuple(ty), + Type::Verbatim(ty) => self.type_verbatim(ty), + _ => unimplemented!("unknown Type"), + } + } + + fn type_array(&mut self, ty: &TypeArray) { + self.word("["); + self.ty(&ty.elem); + self.word("; "); + self.expr(&ty.len, FixupContext::NONE); + self.word("]"); + } + + fn type_bare_fn(&mut self, ty: &TypeBareFn) { + if let Some(bound_lifetimes) = &ty.lifetimes { + self.bound_lifetimes(bound_lifetimes); + } + if ty.unsafety.is_some() { + self.word("unsafe "); + } + if let Some(abi) = &ty.abi { + self.abi(abi); + } + self.word("fn("); + self.cbox(INDENT); + self.zerobreak(); + for bare_fn_arg in ty.inputs.iter().delimited() { + self.bare_fn_arg(&bare_fn_arg); + self.trailing_comma(bare_fn_arg.is_last && ty.variadic.is_none()); + } + if let Some(variadic) = &ty.variadic { + self.bare_variadic(variadic); + self.zerobreak(); + } + self.offset(-INDENT); + self.end(); + self.word(")"); + self.return_type(&ty.output); + } + + fn type_group(&mut self, ty: &TypeGroup) { + self.ty(&ty.elem); + } + + fn type_impl_trait(&mut self, ty: &TypeImplTrait) { + self.word("impl "); + for type_param_bound in ty.bounds.iter().delimited() { + if !type_param_bound.is_first { + self.word(" + "); + } + self.type_param_bound(&type_param_bound); + } + } + + fn type_infer(&mut self, ty: &TypeInfer) { + let _ = ty; + self.word("_"); + } + + fn type_macro(&mut self, ty: &TypeMacro) { + let semicolon = false; + self.mac(&ty.mac, None, semicolon); + } + + fn type_never(&mut self, ty: &TypeNever) { + let _ = ty; + self.word("!"); + } + + fn type_paren(&mut self, ty: &TypeParen) { + self.word("("); + self.ty(&ty.elem); + self.word(")"); + } + + fn type_path(&mut self, ty: &TypePath) { + self.qpath(&ty.qself, &ty.path, PathKind::Type); + } + + fn type_ptr(&mut self, ty: &TypePtr) { + self.word("*"); + if ty.mutability.is_some() { + self.word("mut "); + } else { + self.word("const "); + } + self.ty(&ty.elem); + } + + fn type_reference(&mut self, ty: &TypeReference) { + self.word("&"); + if let Some(lifetime) = &ty.lifetime { + self.lifetime(lifetime); + self.nbsp(); + } + if ty.mutability.is_some() { + self.word("mut "); + } + self.ty(&ty.elem); + } + + fn type_slice(&mut self, ty: &TypeSlice) { + self.word("["); + self.ty(&ty.elem); + self.word("]"); + } + + fn type_trait_object(&mut self, ty: &TypeTraitObject) { + self.word("dyn "); + for type_param_bound in ty.bounds.iter().delimited() { + if !type_param_bound.is_first { + self.word(" + "); + } + self.type_param_bound(&type_param_bound); + } + } + + fn type_tuple(&mut self, ty: &TypeTuple) { + self.word("("); + self.cbox(INDENT); + self.zerobreak(); + for elem in ty.elems.iter().delimited() { + self.ty(&elem); + if ty.elems.len() == 1 { + self.word(","); + self.zerobreak(); + } else { + self.trailing_comma(elem.is_last); + } + } + self.offset(-INDENT); + self.end(); + self.word(")"); + } + + #[cfg(not(feature = "verbatim"))] + fn type_verbatim(&mut self, ty: &TokenStream) { + unimplemented!("Type::Verbatim `{}`", ty); + } + + #[cfg(feature = "verbatim")] + fn type_verbatim(&mut self, tokens: &TokenStream) { + use syn::parse::{Parse, ParseStream, Result}; + use syn::punctuated::Punctuated; + use syn::{token, FieldsNamed, Token, TypeParamBound}; + + enum TypeVerbatim { + Ellipsis, + AnonStruct(AnonStruct), + AnonUnion(AnonUnion), + DynStar(DynStar), + MutSelf(MutSelf), + NotType(NotType), + } + + struct AnonStruct { + fields: FieldsNamed, + } + + struct AnonUnion { + fields: FieldsNamed, + } + + struct DynStar { + bounds: Punctuated, + } + + struct MutSelf { + ty: Option, + } + + struct NotType { + inner: Type, + } + + impl Parse for TypeVerbatim { + fn parse(input: ParseStream) -> Result { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![struct]) { + input.parse::()?; + let fields: FieldsNamed = input.parse()?; + Ok(TypeVerbatim::AnonStruct(AnonStruct { fields })) + } else if lookahead.peek(Token![union]) && input.peek2(token::Brace) { + input.parse::()?; + let fields: FieldsNamed = input.parse()?; + Ok(TypeVerbatim::AnonUnion(AnonUnion { fields })) + } else if lookahead.peek(Token![dyn]) { + input.parse::()?; + input.parse::()?; + let bounds = input.parse_terminated(TypeParamBound::parse, Token![+])?; + Ok(TypeVerbatim::DynStar(DynStar { bounds })) + } else if lookahead.peek(Token![mut]) { + input.parse::()?; + input.parse::()?; + let ty = if input.is_empty() { + None + } else { + input.parse::()?; + let ty: Type = input.parse()?; + Some(ty) + }; + Ok(TypeVerbatim::MutSelf(MutSelf { ty })) + } else if lookahead.peek(Token![!]) { + input.parse::()?; + let inner: Type = input.parse()?; + Ok(TypeVerbatim::NotType(NotType { inner })) + } else if lookahead.peek(Token![...]) { + input.parse::()?; + Ok(TypeVerbatim::Ellipsis) + } else { + Err(lookahead.error()) + } + } + } + + let ty: TypeVerbatim = match syn::parse2(tokens.clone()) { + Ok(ty) => ty, + Err(_) => unimplemented!("Type::Verbatim `{}`", tokens), + }; + + match ty { + TypeVerbatim::Ellipsis => { + self.word("..."); + } + TypeVerbatim::AnonStruct(ty) => { + self.cbox(INDENT); + self.word("struct {"); + self.hardbreak_if_nonempty(); + for field in &ty.fields.named { + self.field(field); + self.word(","); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + TypeVerbatim::AnonUnion(ty) => { + self.cbox(INDENT); + self.word("union {"); + self.hardbreak_if_nonempty(); + for field in &ty.fields.named { + self.field(field); + self.word(","); + self.hardbreak(); + } + self.offset(-INDENT); + self.end(); + self.word("}"); + } + TypeVerbatim::DynStar(ty) => { + self.word("dyn* "); + for type_param_bound in ty.bounds.iter().delimited() { + if !type_param_bound.is_first { + self.word(" + "); + } + self.type_param_bound(&type_param_bound); + } + } + TypeVerbatim::MutSelf(bare_fn_arg) => { + self.word("mut self"); + if let Some(ty) = &bare_fn_arg.ty { + self.word(": "); + self.ty(ty); + } + } + TypeVerbatim::NotType(ty) => { + self.word("!"); + self.ty(&ty.inner); + } + } + } + + pub fn return_type(&mut self, ty: &ReturnType) { + match ty { + ReturnType::Default => {} + ReturnType::Type(_arrow, ty) => { + self.word(" -> "); + self.ty(ty); + } + } + } + + fn bare_fn_arg(&mut self, bare_fn_arg: &BareFnArg) { + self.outer_attrs(&bare_fn_arg.attrs); + if let Some((name, _colon)) = &bare_fn_arg.name { + self.ident(name); + self.word(": "); + } + self.ty(&bare_fn_arg.ty); + } + + fn bare_variadic(&mut self, variadic: &BareVariadic) { + self.outer_attrs(&variadic.attrs); + if let Some((name, _colon)) = &variadic.name { + self.ident(name); + self.word(": "); + } + self.word("..."); + } + + pub fn abi(&mut self, abi: &Abi) { + self.word("extern "); + if let Some(name) = &abi.name { + self.lit_str(name); + self.nbsp(); + } + } +} diff --git a/vendor/prettyplease/tests/test.rs b/vendor/prettyplease/tests/test.rs new file mode 100644 index 00000000..aa6b849f --- /dev/null +++ b/vendor/prettyplease/tests/test.rs @@ -0,0 +1,51 @@ +use indoc::indoc; +use proc_macro2::{Delimiter, Group, TokenStream}; +use quote::quote; + +#[track_caller] +fn test(tokens: TokenStream, expected: &str) { + let syntax_tree: syn::File = syn::parse2(tokens).unwrap(); + let pretty = prettyplease::unparse(&syntax_tree); + assert_eq!(pretty, expected); +} + +#[test] +fn test_parenthesize_cond() { + let s = Group::new(Delimiter::None, quote!(Struct {})); + test( + quote! { + fn main() { + if #s == #s {} + } + }, + indoc! {" + fn main() { + if (Struct {}) == (Struct {}) {} + } + "}, + ); +} + +#[test] +fn test_parenthesize_match_guard() { + let expr_struct = Group::new(Delimiter::None, quote!(Struct {})); + let expr_binary = Group::new(Delimiter::None, quote!(true && false)); + test( + quote! { + fn main() { + match () { + () if let _ = #expr_struct => {} + () if let _ = #expr_binary => {} + } + } + }, + indoc! {" + fn main() { + match () { + () if let _ = Struct {} => {} + () if let _ = (true && false) => {} + } + } + "}, + ); +} diff --git a/vendor/prettyplease/tests/test_precedence.rs b/vendor/prettyplease/tests/test_precedence.rs new file mode 100644 index 00000000..f1eec232 --- /dev/null +++ b/vendor/prettyplease/tests/test_precedence.rs @@ -0,0 +1,900 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::ToTokens as _; +use std::mem; +use std::process::ExitCode; +use syn::punctuated::Punctuated; +use syn::visit_mut::{self, VisitMut}; +use syn::{ + token, AngleBracketedGenericArguments, Arm, BinOp, Block, Expr, ExprArray, ExprAssign, + ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, ExprClosure, + ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop, + ExprMacro, ExprMatch, ExprMethodCall, ExprPath, ExprRange, ExprRawAddr, ExprReference, + ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, + File, GenericArgument, Generics, Item, ItemConst, Label, Lifetime, LifetimeParam, Lit, LitInt, + Macro, MacroDelimiter, Member, Pat, PatWild, Path, PathArguments, PathSegment, + PointerMutability, QSelf, RangeLimits, ReturnType, Stmt, StmtMacro, Token, Type, TypeInfer, + TypeParam, TypePath, UnOp, Visibility, +}; + +struct FlattenParens; + +impl VisitMut for FlattenParens { + fn visit_expr_mut(&mut self, e: &mut Expr) { + while let Expr::Paren(paren) = e { + *e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER); + } + visit_mut::visit_expr_mut(self, e); + } +} + +struct AsIfPrinted; + +impl VisitMut for AsIfPrinted { + fn visit_generics_mut(&mut self, generics: &mut Generics) { + if generics.params.is_empty() { + generics.lt_token = None; + generics.gt_token = None; + } + if let Some(where_clause) = &generics.where_clause { + if where_clause.predicates.is_empty() { + generics.where_clause = None; + } + } + visit_mut::visit_generics_mut(self, generics); + } + + fn visit_lifetime_param_mut(&mut self, param: &mut LifetimeParam) { + if param.bounds.is_empty() { + param.colon_token = None; + } + visit_mut::visit_lifetime_param_mut(self, param); + } + + fn visit_stmt_mut(&mut self, stmt: &mut Stmt) { + if let Stmt::Expr(expr, semi) = stmt { + if let Expr::Macro(e) = expr { + if match e.mac.delimiter { + MacroDelimiter::Brace(_) => true, + MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => semi.is_some(), + } { + let expr = match mem::replace(expr, Expr::PLACEHOLDER) { + Expr::Macro(expr) => expr, + _ => unreachable!(), + }; + *stmt = Stmt::Macro(StmtMacro { + attrs: expr.attrs, + mac: expr.mac, + semi_token: *semi, + }); + } + } + } + visit_mut::visit_stmt_mut(self, stmt); + } + + fn visit_type_param_mut(&mut self, param: &mut TypeParam) { + if param.bounds.is_empty() { + param.colon_token = None; + } + visit_mut::visit_type_param_mut(self, param); + } +} + +#[test] +fn test_permutations() -> ExitCode { + fn iter(depth: usize, f: &mut dyn FnMut(Expr)) { + let span = Span::call_site(); + + // Expr::Path + f(Expr::Path(ExprPath { + // `x` + attrs: Vec::new(), + qself: None, + path: Path::from(Ident::new("x", span)), + })); + if false { + f(Expr::Path(ExprPath { + // `x::` + attrs: Vec::new(), + qself: None, + path: Path { + leading_colon: None, + segments: Punctuated::from_iter([PathSegment { + ident: Ident::new("x", span), + arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { + colon2_token: Some(Token![::](span)), + lt_token: Token![<](span), + args: Punctuated::from_iter([GenericArgument::Type(Type::Path( + TypePath { + qself: None, + path: Path::from(Ident::new("T", span)), + }, + ))]), + gt_token: Token![>](span), + }), + }]), + }, + })); + f(Expr::Path(ExprPath { + // `::CONST` + attrs: Vec::new(), + qself: Some(QSelf { + lt_token: Token![<](span), + ty: Box::new(Type::Path(TypePath { + qself: None, + path: Path::from(Ident::new("T", span)), + })), + position: 1, + as_token: Some(Token![as](span)), + gt_token: Token![>](span), + }), + path: Path { + leading_colon: None, + segments: Punctuated::from_iter([ + PathSegment::from(Ident::new("Trait", span)), + PathSegment::from(Ident::new("CONST", span)), + ]), + }, + })); + } + + let depth = match depth.checked_sub(1) { + Some(depth) => depth, + None => return, + }; + + // Expr::Assign + iter(depth, &mut |expr| { + iter(0, &mut |simple| { + f(Expr::Assign(ExprAssign { + // `x = $expr` + attrs: Vec::new(), + left: Box::new(simple.clone()), + eq_token: Token![=](span), + right: Box::new(expr.clone()), + })); + f(Expr::Assign(ExprAssign { + // `$expr = x` + attrs: Vec::new(), + left: Box::new(expr.clone()), + eq_token: Token![=](span), + right: Box::new(simple), + })); + }); + }); + + // Expr::Binary + iter(depth, &mut |expr| { + iter(0, &mut |simple| { + for op in [ + BinOp::Add(Token![+](span)), + //BinOp::Sub(Token![-](span)), + //BinOp::Mul(Token![*](span)), + //BinOp::Div(Token![/](span)), + //BinOp::Rem(Token![%](span)), + //BinOp::And(Token![&&](span)), + //BinOp::Or(Token![||](span)), + //BinOp::BitXor(Token![^](span)), + //BinOp::BitAnd(Token![&](span)), + //BinOp::BitOr(Token![|](span)), + //BinOp::Shl(Token![<<](span)), + //BinOp::Shr(Token![>>](span)), + //BinOp::Eq(Token![==](span)), + BinOp::Lt(Token![<](span)), + //BinOp::Le(Token![<=](span)), + //BinOp::Ne(Token![!=](span)), + //BinOp::Ge(Token![>=](span)), + //BinOp::Gt(Token![>](span)), + BinOp::ShlAssign(Token![<<=](span)), + ] { + f(Expr::Binary(ExprBinary { + // `x + $expr` + attrs: Vec::new(), + left: Box::new(simple.clone()), + op, + right: Box::new(expr.clone()), + })); + f(Expr::Binary(ExprBinary { + // `$expr + x` + attrs: Vec::new(), + left: Box::new(expr.clone()), + op, + right: Box::new(simple.clone()), + })); + } + }); + }); + + // Expr::Block + f(Expr::Block(ExprBlock { + // `{}` + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::Break + f(Expr::Break(ExprBreak { + // `break` + attrs: Vec::new(), + break_token: Token![break](span), + label: None, + expr: None, + })); + iter(depth, &mut |expr| { + f(Expr::Break(ExprBreak { + // `break $expr` + attrs: Vec::new(), + break_token: Token![break](span), + label: None, + expr: Some(Box::new(expr)), + })); + }); + + // Expr::Call + iter(depth, &mut |expr| { + f(Expr::Call(ExprCall { + // `$expr()` + attrs: Vec::new(), + func: Box::new(expr), + paren_token: token::Paren(span), + args: Punctuated::new(), + })); + }); + + // Expr::Cast + iter(depth, &mut |expr| { + f(Expr::Cast(ExprCast { + // `$expr as T` + attrs: Vec::new(), + expr: Box::new(expr), + as_token: Token![as](span), + ty: Box::new(Type::Path(TypePath { + qself: None, + path: Path::from(Ident::new("T", span)), + })), + })); + }); + + // Expr::Closure + iter(depth, &mut |expr| { + f(Expr::Closure(ExprClosure { + // `|| $expr` + attrs: Vec::new(), + lifetimes: None, + constness: None, + movability: None, + asyncness: None, + capture: None, + or1_token: Token![|](span), + inputs: Punctuated::new(), + or2_token: Token![|](span), + output: ReturnType::Default, + body: Box::new(expr), + })); + }); + + // Expr::Field + iter(depth, &mut |expr| { + f(Expr::Field(ExprField { + // `$expr.field` + attrs: Vec::new(), + base: Box::new(expr), + dot_token: Token![.](span), + member: Member::Named(Ident::new("field", span)), + })); + }); + + // Expr::If + iter(depth, &mut |expr| { + f(Expr::If(ExprIf { + // `if $expr {}` + attrs: Vec::new(), + if_token: Token![if](span), + cond: Box::new(expr), + then_branch: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + else_branch: None, + })); + }); + + // Expr::Let + iter(depth, &mut |expr| { + f(Expr::Let(ExprLet { + attrs: Vec::new(), + let_token: Token![let](span), + pat: Box::new(Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + })), + eq_token: Token![=](span), + expr: Box::new(expr), + })); + }); + + // Expr::Range + f(Expr::Range(ExprRange { + // `..` + attrs: Vec::new(), + start: None, + limits: RangeLimits::HalfOpen(Token![..](span)), + end: None, + })); + iter(depth, &mut |expr| { + f(Expr::Range(ExprRange { + // `..$expr` + attrs: Vec::new(), + start: None, + limits: RangeLimits::HalfOpen(Token![..](span)), + end: Some(Box::new(expr.clone())), + })); + f(Expr::Range(ExprRange { + // `$expr..` + attrs: Vec::new(), + start: Some(Box::new(expr)), + limits: RangeLimits::HalfOpen(Token![..](span)), + end: None, + })); + }); + + // Expr::Reference + iter(depth, &mut |expr| { + f(Expr::Reference(ExprReference { + // `&$expr` + attrs: Vec::new(), + and_token: Token![&](span), + mutability: None, + expr: Box::new(expr), + })); + }); + + // Expr::Return + f(Expr::Return(ExprReturn { + // `return` + attrs: Vec::new(), + return_token: Token![return](span), + expr: None, + })); + iter(depth, &mut |expr| { + f(Expr::Return(ExprReturn { + // `return $expr` + attrs: Vec::new(), + return_token: Token![return](span), + expr: Some(Box::new(expr)), + })); + }); + + // Expr::Try + iter(depth, &mut |expr| { + f(Expr::Try(ExprTry { + // `$expr?` + attrs: Vec::new(), + expr: Box::new(expr), + question_token: Token![?](span), + })); + }); + + // Expr::Unary + iter(depth, &mut |expr| { + for op in [ + UnOp::Deref(Token![*](span)), + //UnOp::Not(Token![!](span)), + //UnOp::Neg(Token![-](span)), + ] { + f(Expr::Unary(ExprUnary { + // `*$expr` + attrs: Vec::new(), + op, + expr: Box::new(expr.clone()), + })); + } + }); + + if false { + // Expr::Array + f(Expr::Array(ExprArray { + // `[]` + attrs: Vec::new(), + bracket_token: token::Bracket(span), + elems: Punctuated::new(), + })); + + // Expr::Async + f(Expr::Async(ExprAsync { + // `async {}` + attrs: Vec::new(), + async_token: Token![async](span), + capture: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::Await + iter(depth, &mut |expr| { + f(Expr::Await(ExprAwait { + // `$expr.await` + attrs: Vec::new(), + base: Box::new(expr), + dot_token: Token![.](span), + await_token: Token![await](span), + })); + }); + + // Expr::Block + f(Expr::Block(ExprBlock { + // `'a: {}` + attrs: Vec::new(), + label: Some(Label { + name: Lifetime::new("'a", span), + colon_token: Token![:](span), + }), + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + iter(depth, &mut |expr| { + f(Expr::Block(ExprBlock { + // `{ $expr }` + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::from([Stmt::Expr(expr.clone(), None)]), + }, + })); + f(Expr::Block(ExprBlock { + // `{ $expr; }` + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::from([Stmt::Expr(expr, Some(Token![;](span)))]), + }, + })); + }); + + // Expr::Break + f(Expr::Break(ExprBreak { + // `break 'a` + attrs: Vec::new(), + break_token: Token![break](span), + label: Some(Lifetime::new("'a", span)), + expr: None, + })); + iter(depth, &mut |expr| { + f(Expr::Break(ExprBreak { + // `break 'a $expr` + attrs: Vec::new(), + break_token: Token![break](span), + label: Some(Lifetime::new("'a", span)), + expr: Some(Box::new(expr)), + })); + }); + + // Expr::Closure + f(Expr::Closure(ExprClosure { + // `|| -> T {}` + attrs: Vec::new(), + lifetimes: None, + constness: None, + movability: None, + asyncness: None, + capture: None, + or1_token: Token![|](span), + inputs: Punctuated::new(), + or2_token: Token![|](span), + output: ReturnType::Type( + Token![->](span), + Box::new(Type::Path(TypePath { + qself: None, + path: Path::from(Ident::new("T", span)), + })), + ), + body: Box::new(Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })), + })); + + // Expr::Const + f(Expr::Const(ExprConst { + // `const {}` + attrs: Vec::new(), + const_token: Token![const](span), + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::Continue + f(Expr::Continue(ExprContinue { + // `continue` + attrs: Vec::new(), + continue_token: Token![continue](span), + label: None, + })); + f(Expr::Continue(ExprContinue { + // `continue 'a` + attrs: Vec::new(), + continue_token: Token![continue](span), + label: Some(Lifetime::new("'a", span)), + })); + + // Expr::ForLoop + iter(depth, &mut |expr| { + f(Expr::ForLoop(ExprForLoop { + // `for _ in $expr {}` + attrs: Vec::new(), + label: None, + for_token: Token![for](span), + pat: Box::new(Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + })), + in_token: Token![in](span), + expr: Box::new(expr.clone()), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + f(Expr::ForLoop(ExprForLoop { + // `'a: for _ in $expr {}` + attrs: Vec::new(), + label: Some(Label { + name: Lifetime::new("'a", span), + colon_token: Token![:](span), + }), + for_token: Token![for](span), + pat: Box::new(Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + })), + in_token: Token![in](span), + expr: Box::new(expr), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + }); + + // Expr::Index + iter(depth, &mut |expr| { + f(Expr::Index(ExprIndex { + // `$expr[0]` + attrs: Vec::new(), + expr: Box::new(expr), + bracket_token: token::Bracket(span), + index: Box::new(Expr::Lit(ExprLit { + attrs: Vec::new(), + lit: Lit::Int(LitInt::new("0", span)), + })), + })); + }); + + // Expr::Loop + f(Expr::Loop(ExprLoop { + // `loop {}` + attrs: Vec::new(), + label: None, + loop_token: Token![loop](span), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + f(Expr::Loop(ExprLoop { + // `'a: loop {}` + attrs: Vec::new(), + label: Some(Label { + name: Lifetime::new("'a", span), + colon_token: Token![:](span), + }), + loop_token: Token![loop](span), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::Macro + f(Expr::Macro(ExprMacro { + // `m!()` + attrs: Vec::new(), + mac: Macro { + path: Path::from(Ident::new("m", span)), + bang_token: Token![!](span), + delimiter: MacroDelimiter::Paren(token::Paren(span)), + tokens: TokenStream::new(), + }, + })); + f(Expr::Macro(ExprMacro { + // `m! {}` + attrs: Vec::new(), + mac: Macro { + path: Path::from(Ident::new("m", span)), + bang_token: Token![!](span), + delimiter: MacroDelimiter::Brace(token::Brace(span)), + tokens: TokenStream::new(), + }, + })); + + // Expr::Match + iter(depth, &mut |expr| { + f(Expr::Match(ExprMatch { + // `match $expr {}` + attrs: Vec::new(), + match_token: Token![match](span), + expr: Box::new(expr.clone()), + brace_token: token::Brace(span), + arms: Vec::new(), + })); + f(Expr::Match(ExprMatch { + // `match x { _ => $expr }` + attrs: Vec::new(), + match_token: Token![match](span), + expr: Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself: None, + path: Path::from(Ident::new("x", span)), + })), + brace_token: token::Brace(span), + arms: Vec::from([Arm { + attrs: Vec::new(), + pat: Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + }), + guard: None, + fat_arrow_token: Token![=>](span), + body: Box::new(expr.clone()), + comma: None, + }]), + })); + f(Expr::Match(ExprMatch { + // `match x { _ if $expr => {} }` + attrs: Vec::new(), + match_token: Token![match](span), + expr: Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself: None, + path: Path::from(Ident::new("x", span)), + })), + brace_token: token::Brace(span), + arms: Vec::from([Arm { + attrs: Vec::new(), + pat: Pat::Wild(PatWild { + attrs: Vec::new(), + underscore_token: Token![_](span), + }), + guard: Some((Token![if](span), Box::new(expr))), + fat_arrow_token: Token![=>](span), + body: Box::new(Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })), + comma: None, + }]), + })); + }); + + // Expr::MethodCall + iter(depth, &mut |expr| { + f(Expr::MethodCall(ExprMethodCall { + // `$expr.method()` + attrs: Vec::new(), + receiver: Box::new(expr.clone()), + dot_token: Token![.](span), + method: Ident::new("method", span), + turbofish: None, + paren_token: token::Paren(span), + args: Punctuated::new(), + })); + f(Expr::MethodCall(ExprMethodCall { + // `$expr.method::()` + attrs: Vec::new(), + receiver: Box::new(expr), + dot_token: Token![.](span), + method: Ident::new("method", span), + turbofish: Some(AngleBracketedGenericArguments { + colon2_token: Some(Token![::](span)), + lt_token: Token![<](span), + args: Punctuated::from_iter([GenericArgument::Type(Type::Path( + TypePath { + qself: None, + path: Path::from(Ident::new("T", span)), + }, + ))]), + gt_token: Token![>](span), + }), + paren_token: token::Paren(span), + args: Punctuated::new(), + })); + }); + + // Expr::RawAddr + iter(depth, &mut |expr| { + f(Expr::RawAddr(ExprRawAddr { + // `&raw const $expr` + attrs: Vec::new(), + and_token: Token![&](span), + raw: Token![raw](span), + mutability: PointerMutability::Const(Token![const](span)), + expr: Box::new(expr), + })); + }); + + // Expr::Struct + f(Expr::Struct(ExprStruct { + // `Struct {}` + attrs: Vec::new(), + qself: None, + path: Path::from(Ident::new("Struct", span)), + brace_token: token::Brace(span), + fields: Punctuated::new(), + dot2_token: None, + rest: None, + })); + + // Expr::TryBlock + f(Expr::TryBlock(ExprTryBlock { + // `try {}` + attrs: Vec::new(), + try_token: Token![try](span), + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::Unsafe + f(Expr::Unsafe(ExprUnsafe { + // `unsafe {}` + attrs: Vec::new(), + unsafe_token: Token![unsafe](span), + block: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + + // Expr::While + iter(depth, &mut |expr| { + f(Expr::While(ExprWhile { + // `while $expr {}` + attrs: Vec::new(), + label: None, + while_token: Token![while](span), + cond: Box::new(expr.clone()), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + f(Expr::While(ExprWhile { + // `'a: while $expr {}` + attrs: Vec::new(), + label: Some(Label { + name: Lifetime::new("'a", span), + colon_token: Token![:](span), + }), + while_token: Token![while](span), + cond: Box::new(expr), + body: Block { + brace_token: token::Brace(span), + stmts: Vec::new(), + }, + })); + }); + + // Expr::Yield + f(Expr::Yield(ExprYield { + // `yield` + attrs: Vec::new(), + yield_token: Token![yield](span), + expr: None, + })); + iter(depth, &mut |expr| { + f(Expr::Yield(ExprYield { + // `yield $expr` + attrs: Vec::new(), + yield_token: Token![yield](span), + expr: Some(Box::new(expr)), + })); + }); + } + } + + let mut failures = 0; + macro_rules! fail { + ($($message:tt)*) => {{ + eprintln!($($message)*); + failures += 1; + return; + }}; + } + let mut assert = |mut original: Expr| { + let span = Span::call_site(); + // `const _: () = $expr;` + let pretty = prettyplease::unparse(&File { + shebang: None, + attrs: Vec::new(), + items: Vec::from([Item::Const(ItemConst { + attrs: Vec::new(), + vis: Visibility::Inherited, + const_token: Token![const](span), + ident: Ident::from(Token![_](span)), + generics: Generics::default(), + colon_token: Token![:](span), + ty: Box::new(Type::Infer(TypeInfer { + underscore_token: Token![_](span), + })), + eq_token: Token![=](span), + expr: Box::new(original.clone()), + semi_token: Token![;](span), + })]), + }); + let mut parsed = match syn::parse_file(&pretty) { + Ok(parsed) => parsed, + _ => fail!("failed to parse: {pretty}{original:#?}"), + }; + let item = match parsed.items.as_mut_slice() { + [Item::Const(item)] => item, + _ => unreachable!(), + }; + let mut parsed = mem::replace(&mut *item.expr, Expr::PLACEHOLDER); + AsIfPrinted.visit_expr_mut(&mut original); + FlattenParens.visit_expr_mut(&mut parsed); + if original != parsed { + fail!( + "before: {}\n{:#?}\nafter: {}\n{:#?}", + original.to_token_stream(), + original, + parsed.to_token_stream(), + parsed, + ); + } + if pretty.contains("(||") { + // https://github.com/dtolnay/prettyplease/issues/99 + return; + } + let no_paren = pretty.replace(['(', ')'], ""); + if pretty != no_paren { + if let Ok(mut parsed2) = syn::parse_file(&no_paren) { + let item = match parsed2.items.as_mut_slice() { + [Item::Const(item)] => item, + _ => unreachable!(), + }; + if original == *item.expr { + fail!("redundant parens: {}", pretty); + } + } + } + }; + + iter(if cfg!(debug_assertions) { 3 } else { 4 }, &mut assert); + if failures > 0 { + eprintln!("FAILURES: {failures}"); + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } +} -- cgit v1.2.3