prettyplease-0.2.6/.cargo_vcs_info.json0000644000000001360000000000100135620ustar { "git": { "sha1": "f69383aff4049036f11f3a3b4b927f28f96fa60f" }, "path_in_vcs": "" }prettyplease-0.2.6/.gitattributes000064400000000000000000000001061046102023000152420ustar 00000000000000cargo-expand/*.rs linguist-generated examples/*.rs linguist-generated prettyplease-0.2.6/.github/FUNDING.yml000064400000000000000000000000201046102023000155170ustar 00000000000000github: dtolnay prettyplease-0.2.6/.github/workflows/ci.yml000064400000000000000000000042041046102023000170650ustar 00000000000000name: CI on: push: pull_request: workflow_dispatch: schedule: [cron: "40 1 * * *"] permissions: contents: read env: RUSTFLAGS: -Dwarnings jobs: pre_ci: uses: dtolnay/.github/.github/workflows/pre_ci.yml@master test: name: Rust ${{matrix.rust}} needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest strategy: fail-fast: false matrix: rust: [nightly, beta, stable, 1.56.0] timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{matrix.rust}} - run: cargo check - run: cargo check --features verbatim - run: cargo test env: RUSTFLAGS: ${{env.RUSTFLAGS}} ${{matrix.rust == 'nightly' && '--cfg exhaustive' || ''}} examples: name: Examples needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly with: components: llvm-tools, rustc-dev, rustfmt - run: cargo run --manifest-path examples/update/Cargo.toml - run: git diff --exit-code - run: cargo run --manifest-path cargo-expand/update/Cargo.toml - run: git diff --exit-code fuzz: name: Fuzz needs: pre_ci if: needs.pre_ci.outputs.continue runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/install@cargo-fuzz - run: cargo fuzz check clippy: name: Clippy runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@clippy - run: cargo clippy --features verbatim -- -Dclippy::all -Dclippy::pedantic outdated: name: Outdated runs-on: ubuntu-latest if: github.event_name != 'pull_request' timeout-minutes: 45 steps: - uses: actions/checkout@v3 - uses: dtolnay/install@cargo-outdated - run: cargo outdated --workspace --exit-code 1 prettyplease-0.2.6/.gitignore000064400000000000000000000000231046102023000143350ustar 00000000000000/target Cargo.lock prettyplease-0.2.6/Cargo.toml0000644000000024470000000000100115670ustar # 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.56" name = "prettyplease" version = "0.2.6" authors = ["David Tolnay "] links = "prettyplease02" exclude = ["cargo-expand"] autoexamples = 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.playground] features = ["verbatim"] [lib] doc-scrape-examples = false [dependencies.proc-macro2] version = "1.0" default-features = false [dependencies.syn] version = "2.0.16" features = ["full"] default-features = false [dev-dependencies.syn] version = "2.0.16" features = ["parsing"] default-features = false [features] verbatim = ["syn/parsing"] prettyplease-0.2.6/Cargo.toml.orig000064400000000000000000000016101046102023000152370ustar 00000000000000[package] name = "prettyplease" version = "0.2.6" authors = ["David Tolnay "] autoexamples = false categories = ["development-tools"] description = "A minimal `syn` syntax tree pretty-printer" documentation = "https://docs.rs/prettyplease" edition = "2021" exclude = ["cargo-expand"] keywords = ["rustfmt"] license = "MIT OR Apache-2.0" links = "prettyplease02" repository = "https://github.com/dtolnay/prettyplease" rust-version = "1.56" [features] verbatim = ["syn/parsing"] [dependencies] proc-macro2 = { version = "1.0", default-features = false } syn = { version = "2.0.16", default-features = false, features = ["full"] } [dev-dependencies] syn = { version = "2.0.16", default-features = false, features = ["parsing"] } [lib] doc-scrape-examples = false [package.metadata.playground] features = ["verbatim"] [workspace] members = ["cargo-expand/update", "examples/update"] prettyplease-0.2.6/LICENSE-APACHE000064400000000000000000000227731046102023000143110ustar 00000000000000 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 prettyplease-0.2.6/LICENSE-MIT000064400000000000000000000017771046102023000140220ustar 00000000000000Permission 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. prettyplease-0.2.6/README.md000064400000000000000000000346521046102023000136430ustar 00000000000000prettyplease::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 formattted 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. prettyplease-0.2.6/build.rs000064400000000000000000000002041046102023000140130ustar 00000000000000fn main() { println!("cargo:rerun-if-changed=build.rs"); println!(concat!("cargo:VERSION=", env!("CARGO_PKG_VERSION"))); } prettyplease-0.2.6/examples/.tokeignore000064400000000000000000000000051046102023000163320ustar 00000000000000*.rs prettyplease-0.2.6/examples/input.rs000064400000000000000000000366271046102023000157130ustar 00000000000000use 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)) } } prettyplease-0.2.6/examples/output.prettyplease.rs000064400000000000000000000440061046102023000206220ustar 00000000000000use 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)) } } prettyplease-0.2.6/examples/output.rustc.rs000064400000000000000000000437131046102023000172450ustar 00000000000000use 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)) } } prettyplease-0.2.6/examples/output.rustfmt.rs000064400000000000000000000424421046102023000176070ustar 00000000000000use 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)) } } prettyplease-0.2.6/src/algorithm.rs000064400000000000000000000276361046102023000155130ustar 00000000000000// 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: Option, 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(); } } 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(); } fn check_stream(&mut self) { while self.right_total - self.left_total > self.space { if *self.scan_stack.front().unwrap() == self.buf.index_of_first() { 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 let Some(post_break) = token.post_break { self.print_indent(); self.out.push(post_break); self.space -= post_break.len_utf8() 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; } } prettyplease-0.2.6/src/attr.rs000064400000000000000000000220721046102023000144640ustar 00000000000000use crate::algorithm::Printer; 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); } 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 } prettyplease-0.2.6/src/convenience.rs000064400000000000000000000043661046102023000160140ustar 00000000000000use 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() }); } } prettyplease-0.2.6/src/data.rs000064400000000000000000000045601046102023000144250ustar 00000000000000use crate::algorithm::Printer; 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); } } 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(") "); } } prettyplease-0.2.6/src/expr.rs000064400000000000000000001130651046102023000144730ustar 00000000000000use crate::algorithm::{BreakToken, Printer}; use crate::attr; use crate::iter::IterDelimited; use crate::path::PathKind; 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, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, Index, Label, Member, RangeLimits, ReturnType, Stmt, Token, UnOp, }; impl Printer { pub fn expr(&mut self, expr: &Expr) { match expr { Expr::Array(expr) => self.expr_array(expr), Expr::Assign(expr) => self.expr_assign(expr), Expr::Async(expr) => self.expr_async(expr), Expr::Await(expr) => self.expr_await(expr, false), Expr::Binary(expr) => self.expr_binary(expr), Expr::Block(expr) => self.expr_block(expr), Expr::Break(expr) => self.expr_break(expr), Expr::Call(expr) => self.expr_call(expr, false), Expr::Cast(expr) => self.expr_cast(expr), Expr::Closure(expr) => self.expr_closure(expr), Expr::Const(expr) => self.expr_const(expr), Expr::Continue(expr) => self.expr_continue(expr), Expr::Field(expr) => self.expr_field(expr, false), Expr::ForLoop(expr) => self.expr_for_loop(expr), Expr::Group(expr) => self.expr_group(expr), Expr::If(expr) => self.expr_if(expr), Expr::Index(expr) => self.expr_index(expr, false), Expr::Infer(expr) => self.expr_infer(expr), Expr::Let(expr) => self.expr_let(expr), 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, false), Expr::Paren(expr) => self.expr_paren(expr), Expr::Path(expr) => self.expr_path(expr), Expr::Range(expr) => self.expr_range(expr), Expr::Reference(expr) => self.expr_reference(expr), Expr::Repeat(expr) => self.expr_repeat(expr), Expr::Return(expr) => self.expr_return(expr), Expr::Struct(expr) => self.expr_struct(expr), Expr::Try(expr) => self.expr_try(expr, false), Expr::TryBlock(expr) => self.expr_try_block(expr), Expr::Tuple(expr) => self.expr_tuple(expr), Expr::Unary(expr) => self.expr_unary(expr), Expr::Unsafe(expr) => self.expr_unsafe(expr), Expr::Verbatim(expr) => self.expr_verbatim(expr), Expr::While(expr) => self.expr_while(expr), Expr::Yield(expr) => self.expr_yield(expr), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => unimplemented!("unknown Expr"), } } pub fn expr_beginning_of_line(&mut self, expr: &Expr, beginning_of_line: bool) { match expr { Expr::Await(expr) => self.expr_await(expr, beginning_of_line), Expr::Field(expr) => self.expr_field(expr, beginning_of_line), Expr::Index(expr) => self.expr_index(expr, beginning_of_line), Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line), Expr::Try(expr) => self.expr_try(expr, beginning_of_line), _ => self.expr(expr), } } fn subexpr(&mut self, expr: &Expr, beginning_of_line: bool) { match expr { Expr::Await(expr) => self.subexpr_await(expr, beginning_of_line), Expr::Call(expr) => self.subexpr_call(expr), Expr::Field(expr) => self.subexpr_field(expr, beginning_of_line), Expr::Index(expr) => self.subexpr_index(expr, beginning_of_line), Expr::MethodCall(expr) => self.subexpr_method_call(expr, beginning_of_line, false), Expr::Try(expr) => self.subexpr_try(expr, beginning_of_line), _ => { self.cbox(-INDENT); self.expr(expr); self.end(); } } } fn wrap_exterior_struct(&mut self, expr: &Expr) { let needs_paren = contains_exterior_struct_lit(expr); if needs_paren { self.word("("); } self.cbox(0); self.expr(expr); if needs_paren { self.word(")"); } if needs_newline_if_wrap(expr) { self.space(); } else { self.nbsp(); } self.end(); } fn expr_array(&mut self, expr: &ExprArray) { self.outer_attrs(&expr.attrs); self.word("["); self.cbox(INDENT); self.zerobreak(); for element in expr.elems.iter().delimited() { self.expr(&element); self.trailing_comma(element.is_last); } self.offset(-INDENT); self.end(); self.word("]"); } fn expr_assign(&mut self, expr: &ExprAssign) { self.outer_attrs(&expr.attrs); self.ibox(0); self.expr(&expr.left); self.word(" = "); self.expr(&expr.right); 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) { self.outer_attrs(&expr.attrs); self.cbox(INDENT); self.subexpr_await(expr, beginning_of_line); self.end(); } fn subexpr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) { self.subexpr(&expr.base, beginning_of_line); self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); self.word(".await"); } fn expr_binary(&mut self, expr: &ExprBinary) { self.outer_attrs(&expr.attrs); self.ibox(INDENT); self.ibox(-INDENT); self.expr(&expr.left); self.end(); self.space(); self.binary_operator(&expr.op); self.nbsp(); self.expr(&expr.right); 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) { 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.expr(value); } } fn expr_call(&mut self, expr: &ExprCall, beginning_of_line: bool) { self.outer_attrs(&expr.attrs); self.expr_beginning_of_line(&expr.func, beginning_of_line); self.word("("); self.call_args(&expr.args); self.word(")"); } fn subexpr_call(&mut self, expr: &ExprCall) { self.subexpr(&expr.func, false); self.word("("); self.call_args(&expr.args); self.word(")"); } fn expr_cast(&mut self, expr: &ExprCast) { self.outer_attrs(&expr.attrs); self.ibox(INDENT); self.ibox(-INDENT); self.expr(&expr.expr); self.end(); self.space(); self.word("as "); self.ty(&expr.ty); self.end(); } fn expr_closure(&mut self, expr: &ExprClosure) { 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); self.scan_break(BreakToken { pre_break: Some('{'), ..BreakToken::default() }); self.expr(&expr.body); self.scan_break(BreakToken { offset: -INDENT, pre_break: stmt::add_semi(&expr.body).then(|| ';'), post_break: Some('}'), ..BreakToken::default() }); self.end(); } else { self.expr(&expr.body); } } 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(); self.expr(&expr.body); } } 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) { self.outer_attrs(&expr.attrs); self.cbox(INDENT); self.subexpr_field(expr, beginning_of_line); self.end(); } fn subexpr_field(&mut self, expr: &ExprField, beginning_of_line: bool) { self.subexpr(&expr.base, beginning_of_line); self.zerobreak_unless_short_ident(beginning_of_line, &expr.base); 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.wrap_exterior_struct(&expr.expr); self.word("{"); self.neverbreak(); self.cbox(INDENT); self.hardbreak_if_nonempty(); self.inner_attrs(&expr.attrs); for stmt in &expr.body.stmts { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); self.end(); } fn expr_group(&mut self, expr: &ExprGroup) { self.outer_attrs(&expr.attrs); self.expr(&expr.expr); } fn expr_if(&mut self, expr: &ExprIf) { self.outer_attrs(&expr.attrs); self.cbox(INDENT); self.word("if "); self.cbox(-INDENT); self.wrap_exterior_struct(&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.wrap_exterior_struct(&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.word("{"); self.space(); self.ibox(INDENT); self.expr(other); self.end(); self.space(); self.offset(-INDENT); self.word("}"); } } break; } } else if expr.then_branch.stmts.is_empty() { self.word("{}"); } else { self.word("{"); self.hardbreak(); for stmt in &expr.then_branch.stmts { self.stmt(stmt); } self.offset(-INDENT); self.word("}"); } self.end(); } fn expr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { self.outer_attrs(&expr.attrs); self.expr_beginning_of_line(&expr.expr, beginning_of_line); self.word("["); self.expr(&expr.index); self.word("]"); } fn subexpr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) { self.subexpr(&expr.expr, beginning_of_line); self.word("["); self.expr(&expr.index); self.word("]"); } fn expr_infer(&mut self, expr: &ExprInfer) { self.outer_attrs(&expr.attrs); self.word("_"); } fn expr_let(&mut self, expr: &ExprLet) { self.outer_attrs(&expr.attrs); self.ibox(INDENT); self.word("let "); self.ibox(-INDENT); self.pat(&expr.pat); self.end(); self.space(); self.word("= "); let needs_paren = contains_exterior_struct_lit(&expr.expr); if needs_paren { self.word("("); } self.expr(&expr.expr); if needs_paren { self.word(")"); } 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 { self.stmt(stmt); } 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.wrap_exterior_struct(&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) { self.outer_attrs(&expr.attrs); self.cbox(INDENT); let unindent_call_args = beginning_of_line && is_short_ident(&expr.receiver); self.subexpr_method_call(expr, beginning_of_line, unindent_call_args); self.end(); } fn subexpr_method_call( &mut self, expr: &ExprMethodCall, beginning_of_line: bool, unindent_call_args: bool, ) { self.subexpr(&expr.receiver, beginning_of_line); self.zerobreak_unless_short_ident(beginning_of_line, &expr.receiver); 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); 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) { self.outer_attrs(&expr.attrs); if let Some(start) = &expr.start { self.expr(start); } self.word(match expr.limits { RangeLimits::HalfOpen(_) => "..", RangeLimits::Closed(_) => "..=", }); if let Some(end) = &expr.end { self.expr(end); } } fn expr_reference(&mut self, expr: &ExprReference) { self.outer_attrs(&expr.attrs); self.word("&"); if expr.mutability.is_some() { self.word("mut "); } self.expr(&expr.expr); } fn expr_repeat(&mut self, expr: &ExprRepeat) { self.outer_attrs(&expr.attrs); self.word("["); self.expr(&expr.expr); self.word("; "); self.expr(&expr.len); self.word("]"); } fn expr_return(&mut self, expr: &ExprReturn) { self.outer_attrs(&expr.attrs); self.word("return"); if let Some(value) = &expr.expr { self.nbsp(); self.expr(value); } } 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); self.space(); } self.offset(-INDENT); self.end_with_max_width(34); self.word("}"); } fn expr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { self.outer_attrs(&expr.attrs); self.expr_beginning_of_line(&expr.expr, beginning_of_line); self.word("?"); } fn subexpr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) { self.subexpr(&expr.expr, beginning_of_line); 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); 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) { self.outer_attrs(&expr.attrs); self.unary_operator(&expr.op); self.expr(&expr.expr); } 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) { if !expr.is_empty() { unimplemented!("Expr::Verbatim `{}`", expr); } } #[cfg(feature = "verbatim")] fn expr_verbatim(&mut self, tokens: &TokenStream) { use syn::parse::{Parse, ParseStream, Result}; use syn::{parenthesized, Ident}; enum ExprVerbatim { Empty, Builtin(Builtin), RawReference(RawReference), } struct Builtin { name: Ident, args: TokenStream, } struct RawReference { mutable: bool, expr: Expr, } mod kw { syn::custom_keyword!(builtin); syn::custom_keyword!(raw); } impl Parse for ExprVerbatim { fn parse(input: ParseStream) -> Result { let lookahead = input.lookahead1(); if input.is_empty() { Ok(ExprVerbatim::Empty) } else if lookahead.peek(kw::builtin) { input.parse::()?; input.parse::()?; let name: Ident = input.parse()?; let args; parenthesized!(args in input); let args: TokenStream = args.parse()?; Ok(ExprVerbatim::Builtin(Builtin { name, args })) } else if lookahead.peek(Token![&]) { input.parse::()?; input.parse::()?; let mutable = input.parse::>()?.is_some(); if !mutable { input.parse::()?; } let expr: Expr = input.parse()?; Ok(ExprVerbatim::RawReference(RawReference { mutable, expr })) } 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::Builtin(expr) => { 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(")"); } ExprVerbatim::RawReference(expr) => { self.word("&raw "); self.word(if expr.mutable { "mut " } else { "const " }); self.expr(&expr.expr); } } } 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.wrap_exterior_struct(&expr.cond); self.word("{"); self.neverbreak(); self.cbox(INDENT); self.hardbreak_if_nonempty(); self.inner_attrs(&expr.attrs); for stmt in &expr.body.stmts { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); } fn expr_yield(&mut self, expr: &ExprYield) { self.outer_attrs(&expr.attrs); self.word("yield"); if let Some(value) = &expr.expr { self.nbsp(); self.expr(value); } } 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); 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); } 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 { self.nbsp(); 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 { self.stmt(stmt); } self.offset(-INDENT); self.end(); self.word("}"); self.end(); } else { self.nbsp(); self.neverbreak(); self.cbox(INDENT); self.scan_break(BreakToken { pre_break: Some('{'), ..BreakToken::default() }); self.expr_beginning_of_line(body, true); self.scan_break(BreakToken { offset: -INDENT, pre_break: stmt::add_semi(body).then(|| ';'), post_break: Some('}'), no_break: requires_terminator(body).then(|| ','), ..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); } _ => { self.cbox(INDENT); self.zerobreak(); for arg in args.iter().delimited() { self.expr(&arg); 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.get(0), block.stmts.get(1)) { (Some(Stmt::Expr(expr, None)), None) if stmt::break_after(expr) => { self.ibox(0); self.expr_beginning_of_line(expr, true); self.end(); self.space(); } _ => { for stmt in &block.stmts { self.stmt(stmt); } } } 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 { 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(_) => ">>=", #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => unimplemented!("unknown BinOp"), }); } fn unary_operator(&mut self, op: &UnOp) { self.word(match op { UnOp::Deref(_) => "*", UnOp::Not(_) => "!", UnOp::Neg(_) => "-", #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => unimplemented!("unknown UnOp"), }); } fn zerobreak_unless_short_ident(&mut self, beginning_of_line: bool, expr: &Expr) { if beginning_of_line && is_short_ident(expr) { return; } self.zerobreak(); } } pub fn requires_terminator(expr: &Expr) -> bool { // see https://github.com/rust-lang/rust/blob/a266f1199/compiler/rustc_ast/src/util/classify.rs#L7-L26 match expr { Expr::If(_) | Expr::Match(_) | Expr::Block(_) | Expr::Unsafe(_) // both under ExprKind::Block in rustc | Expr::While(_) | Expr::Loop(_) | Expr::ForLoop(_) | Expr::TryBlock(_) | Expr::Const(_) => false, Expr::Array(_) | Expr::Assign(_) | Expr::Async(_) | Expr::Await(_) | Expr::Binary(_) | Expr::Break(_) | Expr::Call(_) | Expr::Cast(_) | Expr::Closure(_) | Expr::Continue(_) | Expr::Field(_) | Expr::Group(_) | Expr::Index(_) | Expr::Infer(_) | Expr::Let(_) | Expr::Lit(_) | Expr::Macro(_) | Expr::MethodCall(_) | Expr::Paren(_) | Expr::Path(_) | Expr::Range(_) | Expr::Reference(_) | Expr::Repeat(_) | Expr::Return(_) | Expr::Struct(_) | Expr::Try(_) | Expr::Tuple(_) | Expr::Unary(_) | Expr::Verbatim(_) | Expr::Yield(_) => true, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => true, } } // Expressions that syntactically contain an "exterior" struct literal i.e. not // surrounded by any parens or other delimiters. For example `X { y: 1 }`, `X { // y: 1 }.method()`, `foo == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X // { y: 1 }) == foo` does not. fn contains_exterior_struct_lit(expr: &Expr) -> bool { match expr { Expr::Struct(_) => true, Expr::Assign(ExprAssign { left, right, .. }) | Expr::Binary(ExprBinary { left, right, .. }) => { // X { y: 1 } + X { y: 2 } contains_exterior_struct_lit(left) || contains_exterior_struct_lit(right) } Expr::Await(ExprAwait { base: e, .. }) | Expr::Cast(ExprCast { expr: e, .. }) | Expr::Field(ExprField { base: e, .. }) | Expr::Index(ExprIndex { expr: e, .. }) | Expr::MethodCall(ExprMethodCall { receiver: e, .. }) | Expr::Reference(ExprReference { expr: e, .. }) | Expr::Unary(ExprUnary { expr: e, .. }) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(e) } Expr::Array(_) | Expr::Async(_) | Expr::Block(_) | Expr::Break(_) | Expr::Call(_) | Expr::Closure(_) | Expr::Const(_) | Expr::Continue(_) | Expr::ForLoop(_) | Expr::Group(_) | Expr::If(_) | Expr::Infer(_) | Expr::Let(_) | Expr::Lit(_) | Expr::Loop(_) | Expr::Macro(_) | Expr::Match(_) | Expr::Paren(_) | Expr::Path(_) | Expr::Range(_) | Expr::Repeat(_) | Expr::Return(_) | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unsafe(_) | Expr::Verbatim(_) | Expr::While(_) | Expr::Yield(_) => false, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => false, } } fn needs_newline_if_wrap(expr: &Expr) -> bool { match expr { 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::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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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 { 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::Group(_) | 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::Reference(_) | Expr::Repeat(_) | Expr::Return(_) | Expr::Try(_) | Expr::Unary(_) | Expr::Verbatim(_) | Expr::While(_) | Expr::Yield(_) => false, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => false, } } prettyplease-0.2.6/src/file.rs000064400000000000000000000006111046102023000144240ustar 00000000000000use 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(); } } prettyplease-0.2.6/src/generics.rs000064400000000000000000000251361046102023000153150ustar 00000000000000use crate::algorithm::Printer; use crate::iter::IterDelimited; use crate::path::PathKind; use crate::INDENT; use proc_macro2::TokenStream; use std::ptr; use syn::{ BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeParam, 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 { TypeParamBound::Trait(trait_bound) => { let tilde_const = false; self.trait_bound(trait_bound, tilde_const); } TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime), TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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 { 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) }; content.parse::()?; content.parse::()?; let mut bound: TraitBound = content.parse()?; bound.paren_token = paren_token; Ok(TypeParamBoundVerbatim::TildeConst(bound)) } } let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) { Ok(bound) => bound, Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens), }; match bound { 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.expr(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 { WherePredicate::Type(predicate) => self.predicate_type(predicate), WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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(); } } prettyplease-0.2.6/src/item.rs000064400000000000000000001575651046102023000144700ustar 00000000000000use crate::algorithm::Printer; use crate::iter::IterDelimited; 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 { 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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); 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); 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 { self.stmt(stmt); } 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 = true; 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); 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, 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); } 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::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 { 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 { 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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); 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 = true; 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::{Attribute, Token, Visibility}; use verbatim::{FlexibleItemFn, FlexibleItemStatic, FlexibleItemType, WhereClauseLocation}; enum ForeignItemVerbatim { Empty, FnFlexible(FlexibleItemFn), StaticFlexible(FlexibleItemStatic), TypeFlexible(FlexibleItemType), } impl Parse for ForeignItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(ForeignItemVerbatim::Empty); } let attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let defaultness = false; let lookahead = input.lookahead1(); if lookahead.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(ForeignItemVerbatim::FnFlexible(flexible_item)) } else if lookahead.peek(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::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 { 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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); } 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); 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 { self.stmt(stmt); } 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 = true; 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, Token, Visibility}; use verbatim::{FlexibleItemType, WhereClauseLocation}; enum TraitItemVerbatim { Empty, 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); } 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![type]) { let flexible_item = FlexibleItemType::parse( attrs, vis, defaultness, input, WhereClauseLocation::AfterEq, )?; Ok(TraitItemVerbatim::TypeFlexible(flexible_item)) } else if (lookahead.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::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 { 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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); 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); 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 { self.stmt(stmt); } 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 = true; 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, ConstFlexible(FlexibleItemConst), FnFlexible(FlexibleItemFn), TypeFlexible(FlexibleItemType), } impl Parse for ImplItemVerbatim { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Ok(ImplItemVerbatim::Empty); } 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::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) { if signature.constness.is_some() { self.word("const "); } if signature.asyncness.is_some() { self.word("async "); } 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 { StaticMutability::Mut(_) => self.word("mut "), StaticMutability::None => {} #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => unimplemented!("unknown StaticMutability"), } } } #[cfg(feature = "verbatim")] mod verbatim { use crate::algorithm::Printer; use crate::iter::IterDelimited; use crate::INDENT; use syn::ext::IdentExt; use syn::parse::{ParseStream, Result}; use syn::{ braced, token, Attribute, Block, Expr, Generics, Ident, Signature, StaticMutability, Stmt, Token, Type, TypeParamBound, Visibility, WhereClause, }; pub struct FlexibleItemConst { pub attrs: Vec, pub vis: Visibility, pub defaultness: bool, pub ident: Ident, pub ty: Type, } pub struct FlexibleItemFn { pub attrs: Vec, pub vis: Visibility, pub defaultness: bool, pub sig: Signature, pub body: Option>, } pub struct FlexibleItemStatic { pub attrs: Vec, pub vis: Visibility, 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 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)?; input.parse::()?; let ty: Type = input.parse()?; input.parse::()?; Ok(FlexibleItemConst { attrs, vis, defaultness, ident, ty, }) } } impl FlexibleItemFn { pub fn parse( mut attrs: Vec, vis: Visibility, defaultness: bool, input: ParseStream, ) -> Result { let sig: Signature = input.parse()?; 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, sig, body, }) } } impl FlexibleItemStatic { pub fn parse(attrs: Vec, vis: Visibility, input: ParseStream) -> Result { 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, 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 Printer { pub fn flexible_item_const(&mut self, item: &FlexibleItemConst) { self.outer_attrs(&item.attrs); self.cbox(0); self.visibility(&item.vis); if item.defaultness { self.word("default "); } self.word("const "); self.ident(&item.ident); self.word(": "); self.ty(&item.ty); self.word(";"); 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); 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 { self.stmt(stmt); } 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.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); } 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(); } } } prettyplease-0.2.6/src/iter.rs000064400000000000000000000016541046102023000144600ustar 00000000000000use 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 } } prettyplease-0.2.6/src/lib.rs000064400000000000000000000410631046102023000142610ustar 00000000000000//! [![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 formattted 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.6")] #![allow( 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::similar_names, 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 convenience; mod data; mod expr; mod file; mod generics; mod item; mod iter; mod lifetime; mod lit; mod mac; mod pat; mod path; 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() } prettyplease-0.2.6/src/lifetime.rs000064400000000000000000000002751046102023000153110ustar 00000000000000use crate::algorithm::Printer; use syn::Lifetime; impl Printer { pub fn lifetime(&mut self, lifetime: &Lifetime) { self.word("'"); self.ident(&lifetime.ident); } } prettyplease-0.2.6/src/lit.rs000064400000000000000000000030341046102023000142770ustar 00000000000000use crate::algorithm::Printer; use proc_macro2::Literal; use syn::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; impl Printer { pub fn lit(&mut self, lit: &Lit) { match lit { Lit::Str(lit) => self.lit_str(lit), Lit::ByteStr(lit) => self.lit_byte_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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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_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()); } } prettyplease-0.2.6/src/mac.rs000064400000000000000000000203521046102023000142510ustar 00000000000000use 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; } } 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 { match mac.delimiter { MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => self.word(";"), MacroDelimiter::Brace(_) => {} } } } 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, 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(_)) => (false, if matcher { DollarIdent } else { 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(_)) => (state != Dot, Ident), (_, Token::Punct(',' | ';', _)) => (false, Other), (_, Token::Punct('.', _)) if !matcher => (state != Ident && state != Delim, Dot), (_, Token::Punct(':', Spacing::Joint)) => (state != Ident, 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; } } } 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, } } prettyplease-0.2.6/src/pat.rs000064400000000000000000000165541046102023000143060ustar 00000000000000use crate::algorithm::Printer; 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 { 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), 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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 { 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 { Err(lookahead.error()) } } } let pat: PatVerbatim = match syn::parse2(tokens.clone()) { Ok(pat) => pat, Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens), }; match pat { 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); } } prettyplease-0.2.6/src/path.rs000064400000000000000000000151501046102023000144450ustar 00000000000000use crate::algorithm::Printer; use crate::iter::IterDelimited; use crate::INDENT; use std::ptr; use syn::{ AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, Expr, 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 { GenericArgument::Lifetime(lifetime) => self.lifetime(lifetime), GenericArgument::Type(ty) => self.ty(ty), GenericArgument::Const(expr) => { match expr { Expr::Lit(expr) => self.expr_lit(expr), Expr::Block(expr) => self.expr_block(expr), // ERROR CORRECTION: Add braces to make sure that the // generated code is valid. _ => { self.word("{"); self.expr(expr); self.word("}"); } } } GenericArgument::AssocType(assoc) => self.assoc_type(assoc), GenericArgument::AssocConst(assoc) => self.assoc_const(assoc), GenericArgument::Constraint(constraint) => self.constraint(constraint), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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 { GenericArgument::Lifetime(_) => Group::First, GenericArgument::Type(_) | GenericArgument::Const(_) | GenericArgument::AssocType(_) | GenericArgument::AssocConst(_) | GenericArgument::Constraint(_) => Group::Second, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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.expr(&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 = match qself { Some(qself) => qself, None => { 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); } } } prettyplease-0.2.6/src/ring.rs000064400000000000000000000032601046102023000144470ustar 00000000000000use std::collections::VecDeque; use std::ops::{Index, IndexMut}; 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_of_first(&self) -> usize { self.offset } 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()] } } prettyplease-0.2.6/src/stmt.rs000064400000000000000000000143171046102023000145040ustar 00000000000000use crate::algorithm::Printer; use crate::INDENT; use syn::{BinOp, Expr, Stmt}; impl Printer { pub fn stmt(&mut self, stmt: &Stmt) { 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.expr(&local_init.expr); if let Some((_else, diverge)) = &local_init.diverge { self.word(" else "); if let Expr::Block(expr) = diverge.as_ref() { self.small_block(&expr.block, &[]); } else { self.word("{"); self.space(); self.ibox(INDENT); self.expr(diverge); self.end(); self.space(); self.offset(-INDENT); self.word("}"); } } } self.word(";"); self.end(); 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, true); if add_semi(expr) { self.word(";"); } self.end(); self.hardbreak(); } else { self.expr_beginning_of_line(expr, true); } } 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, true); if !remove_semi(expr) { self.word(";"); } self.end(); self.hardbreak(); } Stmt::Macro(stmt) => { self.outer_attrs(&stmt.attrs); let semicolon = true; self.mac(&stmt.mac, None, semicolon); self.hardbreak(); } } } } pub fn add_semi(expr: &Expr) -> bool { match expr { Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => { true } Expr::Binary(expr) => match expr.op { 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, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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::Reference(_) | Expr::Repeat(_) | Expr::Struct(_) | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unary(_) | Expr::Unsafe(_) | Expr::Verbatim(_) | Expr::While(_) => false, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => 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 { 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::Reference(_) | Expr::Repeat(_) | Expr::Return(_) | Expr::Struct(_) | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unary(_) | Expr::Unsafe(_) | Expr::Verbatim(_) | Expr::Yield(_) => false, #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => false, } } prettyplease-0.2.6/src/token.rs000064400000000000000000000045701046102023000146350ustar 00000000000000use 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), } } } prettyplease-0.2.6/src/ty.rs000064400000000000000000000210771046102023000141520ustar 00000000000000use crate::algorithm::Printer; 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 { 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), #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] _ => unimplemented!("unknown Type"), } } fn type_array(&mut self, ty: &TypeArray) { self.word("["); self.ty(&ty.elem); self.word("; "); self.expr(&ty.len); 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, TypeParamBound}; enum TypeVerbatim { DynStar(DynStar), MutSelf(MutSelf), NotType(NotType), } 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![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 { Err(lookahead.error()) } } } let ty: TypeVerbatim = match syn::parse2(tokens.clone()) { Ok(ty) => ty, Err(_) => unimplemented!("Type::Verbatim `{}`", tokens), }; match ty { 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(); } } }