Merge pull request #28 from fee1-dead-contrib/fmt

use `genemichaels` for formatting
This commit is contained in:
nora 2023-05-26 14:30:13 +02:00 committed by GitHub
commit 42c95c9606
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 248 additions and 4970 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

4
.gitignore vendored
View file

@ -2,4 +2,6 @@ target
/expanded.rs /expanded.rs
/expanded /expanded
/invalid.rs /invalid.rs
/invalid /invalid
.direnv/
g

167
Cargo.lock generated
View file

@ -40,6 +40,16 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cargo-manifest"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce38d2d1efbe0e7180766a872570bc07cd5430a42e713b01006d4afa89912fe"
dependencies = [
"serde",
"toml",
]
[[package]] [[package]]
name = "cargo-minimize" name = "cargo-minimize"
version = "0.1.0" version = "0.1.0"
@ -47,9 +57,9 @@ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"ctrlc", "ctrlc",
"genemichaels",
"libc", "libc",
"owo-colors", "owo-colors",
"prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustfix", "rustfix",
@ -112,6 +122,12 @@ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
[[package]]
name = "convert_case"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.7" version = "0.5.7"
@ -165,6 +181,19 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "derive_more"
version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"syn",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.1" version = "1.8.1"
@ -218,6 +247,31 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "genemichaels"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17de1f67a3bc7d3609c396fc5377c3d0102b7042fab7be3e23b8b0708dfbfa0f"
dependencies = [
"anyhow",
"cargo-manifest",
"clap",
"derive_more",
"markdown",
"proc-macro2",
"quote",
"structre",
"syn",
"threadpool",
"walkdir",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.0"
@ -242,6 +296,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@ -303,6 +367,15 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]]
name = "litrs"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9275e0933cf8bb20f008924c0cb07a0692fe54d8064996520bf998de9eb79aa"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.17"
@ -312,6 +385,15 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "markdown"
version = "1.0.0-alpha.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c45dae11dd8af468c41201ace44dbbb3b1148215ac593cb8f0967b8d8d4b66c"
dependencies = [
"unicode-id",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -398,14 +480,6 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "prettyplease"
version = "0.1.19"
dependencies = [
"proc-macro2",
"syn",
]
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@ -432,9 +506,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.48" version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f" checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -505,6 +579,15 @@ version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]] [[package]]
name = "rustfix" name = "rustfix"
version = "0.6.1" version = "0.6.1"
@ -566,6 +649,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.151" version = "1.0.151"
@ -625,10 +714,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "structre"
version = "1.0.106" version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b" checksum = "f31eab0dcebb0d631c93629c0da9fdce1448123aa15e5e4c08fcd71d4f4fd5f4"
dependencies = [
"anyhow",
"once_cell",
"regex",
"structre_proc_macros",
]
[[package]]
name = "structre_proc_macros"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66e7698a9d57b3a475ce1d6cc37b1be9ee8ed188ec596603c863c06c9e06cf7e"
dependencies = [
"litrs",
"proc-macro2",
"quote",
"regex-syntax",
"syn",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -679,6 +793,25 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"indexmap",
"serde",
]
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.37" version = "0.1.37"
@ -754,6 +887,12 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "unicode-id"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.4" version = "1.0.4"

View file

@ -1,5 +1,5 @@
[workspace] [workspace]
members = ["./", "./prettyplease-forked", "./testsuite"] members = ["./", "./testsuite"]
exclude = ["test-cases/*", "full-tests/*"] exclude = ["test-cases/*", "full-tests/*"]
[package] [package]
@ -20,8 +20,8 @@ lto = "thin"
anyhow = "1.0.65" anyhow = "1.0.65"
clap = { version = "4.0.29", features = ["derive"] } clap = { version = "4.0.29", features = ["derive"] }
ctrlc = "3.2.5" ctrlc = "3.2.5"
genemichaels = "0.1.21"
owo-colors = "3.5.0" owo-colors = "3.5.0"
prettyplease = { path = "./prettyplease-forked", features = ["verbatim"]}
proc-macro2 = { version = "1.0.48", features = ["span-locations"] } proc-macro2 = { version = "1.0.48", features = ["span-locations"] }
quote = "1.0.23" quote = "1.0.23"
rustfix = "0.6.1" rustfix = "0.6.1"

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1684935479,
"narHash": "sha256-6QMMsXMr2nhmOPHdti2j3KRHt+bai2zw+LJfdCl97Mk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f91ee3065de91a3531329a674a45ddcb3467a650",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

18
flake.nix Normal file
View file

@ -0,0 +1,18 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
gcc
];
};
});
}

View file

@ -1,2 +0,0 @@
cargo-expand/*.rs linguist-generated
examples/*.rs linguist-generated

View file

@ -1,2 +0,0 @@
/target
Cargo.lock

View file

@ -1,25 +0,0 @@
[package]
name = "prettyplease"
version = "0.1.19"
authors = ["David Tolnay <dtolnay@gmail.com>"]
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 = "prettyplease01"
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 = "1.0.90", default-features = false, features = ["full"] }
[dev-dependencies]
syn = { version = "1.0.90", default-features = false, features = ["parsing"] }

View file

@ -1,201 +0,0 @@
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
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,23 +0,0 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -1,3 +0,0 @@
fn main() {
println!(concat!("cargo:VERSION=", env!("CARGO_PKG_VERSION")));
}

View file

@ -1,377 +0,0 @@
// 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<char>,
pub post_break: Option<char>,
pub no_break: Option<char>,
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<BufEntry>,
// 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<usize>,
// Stack of blocks-in-progress being flushed by print
print_stack: Vec<PrintFrame>,
// 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 mut 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]
as char,
'-' => '₋',
_ => 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;
}
}

View file

@ -1,233 +0,0 @@
use crate::algorithm::Printer;
use crate::INDENT;
use proc_macro2::{Delimiter, TokenStream, TokenTree};
use syn::{AttrStyle, Attribute, Lit, PathArguments};
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') {
trim_interior_trailing_spaces(&mut doc);
self.word(match attr.style {
AttrStyle::Outer => "/**",
AttrStyle::Inner(_) => "/*!",
});
self.word(doc);
self.word("*/");
} else {
trim_trailing_spaces(&mut doc);
self.word(match attr.style {
AttrStyle::Outer => "///",
AttrStyle::Inner(_) => "//!",
});
self.word(doc);
}
self.hardbreak();
} else if let Some(mut comment) = value_of_attribute("comment", attr) {
if comment.contains('\n') {
trim_interior_trailing_spaces(&mut comment);
self.word("/*");
self.word(comment);
self.word("*/");
} else {
trim_trailing_spaces(&mut comment);
self.word("//");
self.word(comment);
}
self.hardbreak();
} else {
self.word(match attr.style {
AttrStyle::Outer => "#",
AttrStyle::Inner(_) => "#!",
});
self.word("[");
self.path(&attr.path);
self.attr_tokens(attr.tokens.clone());
self.word("]");
self.space();
}
}
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<String> {
let is_doc = attr.path.leading_colon.is_none()
&& attr.path.segments.len() == 1
&& matches!(attr.path.segments[0].arguments, PathArguments::None)
&& attr.path.segments[0].ident == requested;
if !is_doc {
return None;
}
let mut tokens = attr.tokens.clone().into_iter();
match tokens.next() {
Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {}
_ => return None,
}
let literal = match tokens.next() {
Some(TokenTree::Literal(literal)) => literal,
_ => return None,
};
if tokens.next().is_some() {
return None;
}
match Lit::new(literal) {
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;
}

View file

@ -1,98 +0,0 @@
use crate::algorithm::{self, BeginToken, BreakToken, Breaks, Printer};
use std::borrow::Cow;
impl Printer {
pub fn ibox(&mut self, indent: isize) {
self.scan_begin(BeginToken {
offset: indent,
breaks: Breaks::Inconsistent,
});
}
pub fn cbox(&mut self, indent: isize) {
self.scan_begin(BeginToken {
offset: indent,
breaks: Breaks::Consistent,
});
}
pub fn end(&mut self) {
self.scan_end();
}
pub fn word<S: Into<Cow<'static, str>>>(&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()
});
}
}

View file

@ -1,95 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use syn::{
Field, Fields, FieldsUnnamed, PathArguments, Variant, VisCrate, VisPublic, 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(vis) => self.vis_public(vis),
Visibility::Crate(vis) => self.vis_crate(vis),
Visibility::Restricted(vis) => self.vis_restricted(vis),
Visibility::Inherited => {}
}
}
fn vis_public(&mut self, vis: &VisPublic) {
let _ = vis;
self.word("pub ");
}
fn vis_crate(&mut self, vis: &VisCrate) {
let _ = vis;
self.word("crate ");
}
fn vis_restricted(&mut self, vis: &VisRestricted) {
self.word("pub(");
let omit_in = vis.path.leading_colon.is_none()
&& vis.path.segments.len() == 1
&& matches!(vis.path.segments[0].arguments, PathArguments::None)
&& matches!(
vis.path.segments[0].ident.to_string().as_str(),
"self" | "super" | "crate",
);
if !omit_in {
self.word("in ");
}
self.path(&vis.path);
self.word(") ");
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
use crate::algorithm::Printer;
use syn::File;
impl Printer {
pub fn file(&mut self, file: &File) {
self.cbox(0);
if let Some(shebang) = &file.shebang {
self.word(shebang.clone());
self.hardbreak();
}
self.inner_attrs(&file.attrs);
for item in &file.items {
self.item(item);
}
self.end();
}
}

View file

@ -1,280 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use syn::{
BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq,
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.
//
// TODO: ordering rules for const parameters vs type parameters have
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
for param in generics.params.iter().delimited() {
if let GenericParam::Lifetime(_) = *param {
self.generic_param(&param);
self.trailing_comma(param.is_last);
}
}
for param in generics.params.iter().delimited() {
match *param {
GenericParam::Type(_) | GenericParam::Const(_) => {
self.generic_param(&param);
self.trailing_comma(param.is_last);
}
GenericParam::Lifetime(_) => {}
}
}
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_def) => self.lifetime_def(lifetime_def),
GenericParam::Const(const_param) => self.const_param(const_param),
}
}
pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) {
self.word("for<");
for lifetime_def in bound_lifetimes.lifetimes.iter().delimited() {
self.lifetime_def(&lifetime_def);
if !lifetime_def.is_last {
self.word(", ");
}
}
self.word("> ");
}
fn lifetime_def(&mut self, lifetime_def: &LifetimeDef) {
self.outer_attrs(&lifetime_def.attrs);
self.lifetime(&lifetime_def.lifetime);
for lifetime in lifetime_def.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) => self.trait_bound(trait_bound),
TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime),
}
}
fn trait_bound(&mut self, trait_bound: &TraitBound) {
if trait_bound.paren_token.is_some() {
self.word("(");
}
let skip = match trait_bound.path.segments.first() {
Some(segment) if segment.ident == "const" => {
self.word("~const ");
1
}
_ => 0,
};
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().skip(skip).delimited() {
if !segment.is_first || trait_bound.path.leading_colon.is_some() {
self.word("::");
}
self.path_segment(&segment);
}
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("?"),
}
}
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<WhereClause>) {
let hardbreaks = true;
let semi = false;
self.where_clause_impl(where_clause, hardbreaks, semi);
}
pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) {
let hardbreaks = true;
let semi = true;
self.where_clause_impl(where_clause, hardbreaks, semi);
}
pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) {
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<WhereClause>) {
let hardbreaks = false;
let semi = true;
self.where_clause_impl(where_clause, hardbreaks, semi);
}
fn where_clause_impl(
&mut self,
where_clause: &Option<WhereClause>,
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),
WherePredicate::Eq(predicate) => self.predicate_eq(predicate),
}
}
fn predicate_type(&mut self, predicate: &PredicateType) {
if let Some(bound_lifetimes) = &predicate.lifetimes {
self.bound_lifetimes(bound_lifetimes);
}
self.ty(&predicate.bounded_ty);
self.word(":");
if predicate.bounds.len() == 1 {
self.ibox(0);
} else {
self.ibox(INDENT);
}
for type_param_bound in predicate.bounds.iter().delimited() {
if type_param_bound.is_first {
self.nbsp();
} else {
self.space();
self.word("+ ");
}
self.type_param_bound(&type_param_bound);
}
self.end();
}
fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) {
self.lifetime(&predicate.lifetime);
self.word(":");
self.ibox(INDENT);
for lifetime in predicate.bounds.iter().delimited() {
if lifetime.is_first {
self.nbsp();
} else {
self.space();
self.word("+ ");
}
self.lifetime(&lifetime);
}
self.end();
}
fn predicate_eq(&mut self, predicate: &PredicateEq) {
self.ty(&predicate.lhs_ty);
self.word(" = ");
self.ty(&predicate.rhs_ty);
}
}

View file

@ -1,822 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic,
ForeignItemType, ImplItem, ImplItemConst, ImplItemMacro, ImplItemMethod, ImplItemType, Item,
ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMacro2,
ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Pat,
Receiver, Signature, Stmt, TraitItem, TraitItemConst, TraitItemMacro, TraitItemMethod,
TraitItemType, Type, UseGlob, UseGroup, UseName, UsePath, UseRename, UseTree,
};
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::Macro2(item) => self.item_macro2(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.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);
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);
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);
self.mac(&item.mac, item.ident.as_ref());
self.mac_semi_if_needed(&item.mac.delimiter);
self.hardbreak();
}
fn item_macro2(&mut self, item: &ItemMacro2) {
unimplemented!("Item::Macro2 `macro {} {}`", item.ident, item.rules);
}
fn item_mod(&mut self, item: &ItemMod) {
self.outer_attrs(&item.attrs);
self.cbox(INDENT);
self.visibility(&item.vis);
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 ");
if item.mutability.is_some() {
self.word("mut ");
}
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(feature = "verbatim")]
fn item_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
use syn::{Attribute, Token};
enum ItemVerbatim {
Empty,
UnsafeForeignMod(ItemForeignMod),
}
impl Parse for ItemVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
if input.is_empty() {
Ok(ItemVerbatim::Empty)
} else {
let attrs = input.call(Attribute::parse_outer)?;
input.parse::<Token![unsafe]>()?;
let module: ItemForeignMod = input.parse()?;
Ok(ItemVerbatim::UnsafeForeignMod(ItemForeignMod {
attrs,
..module
}))
}
}
}
let item: ItemVerbatim = match syn::parse2(tokens.clone()) {
Ok(item) => item,
Err(_) => return self.word(tokens.to_string()),
};
match item {
ItemVerbatim::Empty => {}
ItemVerbatim::UnsafeForeignMod(item) => {
self.outer_attrs(&item.attrs);
self.cbox(INDENT);
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 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 ");
if foreign_item.mutability.is_some() {
self.word("mut ");
}
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.word(";");
self.end();
self.hardbreak();
}
fn foreign_item_macro(&mut self, foreign_item: &ForeignItemMacro) {
self.outer_attrs(&foreign_item.attrs);
self.mac(&foreign_item.mac, None);
self.mac_semi_if_needed(&foreign_item.mac.delimiter);
self.hardbreak();
}
#[cfg(feature = "verbatim")]
fn foreign_item_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
enum ForeignItemVerbatim {
TypeAlias(ItemType),
}
impl Parse for ForeignItemVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
input.parse().map(ForeignItemVerbatim::TypeAlias)
}
}
let foreign_item: ForeignItemVerbatim = match syn::parse2(tokens.clone()) {
Ok(foreign_item) => foreign_item,
Err(_) => {
self.word(tokens.to_string());
self.hardbreak();
return;
}
};
match foreign_item {
ForeignItemVerbatim::TypeAlias(item) => self.item_type(&item),
}
}
fn trait_item(&mut self, trait_item: &TraitItem) {
match trait_item {
TraitItem::Const(item) => self.trait_item_const(item),
TraitItem::Method(item) => self.trait_item_method(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.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_method(&mut self, trait_item: &TraitItemMethod) {
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.where_clause_oneline(&trait_item.generics.where_clause);
self.word("= ");
self.neverbreak();
self.ty(default);
} else {
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);
self.mac(&trait_item.mac, None);
self.mac_semi_if_needed(&trait_item.mac.delimiter);
self.hardbreak();
}
fn trait_item_verbatim(&mut self, trait_item: &TokenStream) {
self.word(trait_item.to_string());
self.hardbreak();
}
fn impl_item(&mut self, impl_item: &ImplItem) {
match impl_item {
ImplItem::Const(item) => self.impl_item_const(item),
ImplItem::Method(item) => self.impl_item_method(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.word(": ");
self.ty(&impl_item.ty);
self.word(" = ");
self.neverbreak();
self.expr(&impl_item.expr);
self.word(";");
self.end();
self.hardbreak();
}
fn impl_item_method(&mut self, impl_item: &ImplItemMethod) {
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);
if impl_item.block.stmts.len() == 1 {
if let Stmt::Item(Item::Verbatim(verbatim)) = &impl_item.block.stmts[0] {
if verbatim.to_string() == ";" {
self.where_clause_semi(&impl_item.sig.generics.where_clause);
self.end();
self.hardbreak();
return;
}
}
}
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.where_clause_oneline(&impl_item.generics.where_clause);
self.word("= ");
self.neverbreak();
self.ibox(-INDENT);
self.ty(&impl_item.ty);
self.end();
self.word(";");
self.end();
self.hardbreak();
}
fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) {
self.outer_attrs(&impl_item.attrs);
self.mac(&impl_item.mac, None);
self.mac_semi_if_needed(&impl_item.mac.delimiter);
self.hardbreak();
}
fn impl_item_verbatim(&mut self, impl_item: &TokenStream) {
self.word(impl_item.to_string());
self.hardbreak();
}
fn maybe_variadic(&mut self, arg: &FnArg) -> bool {
let pat_type = match arg {
FnArg::Typed(pat_type) => pat_type,
FnArg::Receiver(receiver) => {
self.receiver(receiver);
return false;
}
};
match pat_type.ty.as_ref() {
Type::Verbatim(ty) if ty.to_string() == "..." => {
match pat_type.pat.as_ref() {
Pat::Verbatim(pat) if pat.to_string() == "..." => {
self.outer_attrs(&pat_type.attrs);
self.word("...");
}
_ => self.pat_type(pat_type),
}
true
}
_ => {
self.pat_type(pat_type);
false
}
}
}
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();
let mut last_is_variadic = false;
for input in signature.inputs.iter().delimited() {
last_is_variadic = self.maybe_variadic(&input);
if last_is_variadic {
self.zerobreak();
} else {
self.trailing_comma(input.is_last);
}
}
if signature.variadic.is_some() && !last_is_variadic {
self.word("...");
self.zerobreak();
}
self.offset(-INDENT);
self.end();
self.word(")");
self.cbox(-INDENT);
self.return_type(&signature.output);
self.end();
}
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");
}
}

View file

@ -1,46 +0,0 @@
use std::iter::Peekable;
use std::ops::Deref;
pub struct Delimited<I: Iterator> {
is_first: bool,
iter: Peekable<I>,
}
pub trait IterDelimited: Iterator + Sized {
fn delimited(self) -> Delimited<Self> {
Delimited {
is_first: true,
iter: self.peekable(),
}
}
}
impl<I: Iterator> IterDelimited for I {}
pub struct IteratorItem<T> {
value: T,
pub is_first: bool,
pub is_last: bool,
}
impl<I: Iterator> Iterator for Delimited<I> {
type Item = IteratorItem<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
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<T> Deref for IteratorItem<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}

View file

@ -1,377 +0,0 @@
//! [![github]](https://github.com/dtolnay/prettyplease)&ensp;[![crates-io]](https://crates.io/crates/prettyplease)&ensp;[![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
//!
//! <br>
//!
//! **prettyplease::unparse** &mdash; a minimal `syn` syntax tree pretty-printer
//!
//! <br>
//!
//! # 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 &mdash; 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.
//!
//! <br>
//!
//! # 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 | ❌ | ❌ | 💚 |
//!
//! <br>
//!
//! # 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 &mdash; **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 &mdash; 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 &mdash; 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.
//!
//! <br>
//!
//! # 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.
//!
//! <br>
//!
//! # Example
//!
//! ```
//! // [dependencies]
//! // prettyplease = "0.1"
//! // syn = { version = "1", 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<T, U> Into<U> for T where U: From<T> {
//! 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);
//! }
//! ```
//!
//! <br>
//!
//! # 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`&ndash;`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`&mdash;`end` pairs are represented
//! by `«`&#8288;`»`, inconsistently breaking by ``&#8288;``, `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.
#![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::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()
}

View file

@ -1,9 +0,0 @@
use crate::algorithm::Printer;
use syn::Lifetime;
impl Printer {
pub fn lifetime(&mut self, lifetime: &Lifetime) {
self.word("'");
self.ident(&lifetime.ident);
}
}

View file

@ -1,50 +0,0 @@
use 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),
}
}
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());
}
}

View file

@ -1,220 +0,0 @@
use crate::algorithm::Printer;
use crate::token::Token;
use crate::INDENT;
use proc_macro2::{Delimiter, Spacing, TokenStream};
use syn::{Ident, Macro, MacroDelimiter, PathArguments};
impl Printer {
pub fn mac(&mut self, mac: &Macro, ident: Option<&Ident>) {
let is_macro_rules = mac.path.leading_colon.is_none()
&& mac.path.segments.len() == 1
&& matches!(mac.path.segments[0].arguments, PathArguments::None)
&& mac.path.segments[0].ident == "macro_rules";
if is_macro_rules {
if let Some(ident) = ident {
self.macro_rules(ident, &mac.tokens);
return;
}
}
self.path(&mac.path);
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);
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);
}
pub fn mac_semi_if_needed(&mut self, delimiter: &MacroDelimiter) {
match 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("}");
}
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" | "box" | "break" | "const" | "continue" | "crate" | "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,
}
}

View file

@ -1,210 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
FieldPat, Pat, PatBox, PatIdent, PatLit, PatMacro, PatOr, PatPath, PatRange, PatReference,
PatRest, PatSlice, PatStruct, PatTuple, PatTupleStruct, PatType, PatWild, RangeLimits,
};
impl Printer {
pub fn pat(&mut self, pat: &Pat) {
match pat {
Pat::Box(pat) => self.pat_box(pat),
Pat::Ident(pat) => self.pat_ident(pat),
Pat::Lit(pat) => self.pat_lit(pat),
Pat::Macro(pat) => self.pat_macro(pat),
Pat::Or(pat) => self.pat_or(pat),
Pat::Path(pat) => self.pat_path(pat),
Pat::Range(pat) => self.pat_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_box(&mut self, pat: &PatBox) {
self.outer_attrs(&pat.attrs);
self.word("box ");
self.pat(&pat.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_lit(&mut self, pat: &PatLit) {
self.outer_attrs(&pat.attrs);
self.expr(&pat.expr);
}
fn pat_macro(&mut self, pat: &PatMacro) {
self.outer_attrs(&pat.attrs);
self.mac(&pat.mac, None);
}
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_path(&mut self, pat: &PatPath) {
self.outer_attrs(&pat.attrs);
self.qpath(&pat.qself, &pat.path);
}
fn pat_range(&mut self, pat: &PatRange) {
self.outer_attrs(&pat.attrs);
self.expr(&pat.lo);
match &pat.limits {
RangeLimits::HalfOpen(_) => self.word(".."),
RangeLimits::Closed(_) => self.word("..="),
}
self.expr(&pat.hi);
}
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);
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.dot2_token.is_none());
}
if pat.dot2_token.is_some() {
self.word("..");
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);
self.word("(");
self.cbox(INDENT);
self.zerobreak();
for elem in pat.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);
}
fn pat_verbatim(&mut self, pat: &TokenStream) {
self.word(pat.to_string());
}
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);
}
}

View file

@ -1,185 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use syn::{
AngleBracketedGenericArguments, Binding, Constraint, Expr, GenericArgument,
ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
};
impl Printer {
pub fn path(&mut self, path: &Path) {
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);
}
}
pub fn path_segment(&mut self, segment: &PathSegment) {
self.ident(&segment.ident);
self.path_arguments(&segment.arguments);
}
fn path_arguments(&mut self, arguments: &PathArguments) {
match arguments {
PathArguments::None => {}
PathArguments::AngleBracketed(arguments) => {
self.angle_bracketed_generic_arguments(arguments);
}
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::Binding(binding) => self.binding(binding),
GenericArgument::Constraint(constraint) => self.constraint(constraint),
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("}");
}
}
}
}
}
fn angle_bracketed_generic_arguments(&mut self, generic: &AngleBracketedGenericArguments) {
if generic.args.is_empty() {
return;
}
if generic.colon2_token.is_some() {
self.word("::");
}
self.word("<");
self.cbox(INDENT);
self.zerobreak();
// Print lifetimes before types and consts, all before bindings,
// regardless of their order in self.args.
//
// TODO: ordering rules for const arguments vs type arguments have
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
for arg in generic.args.iter().delimited() {
match *arg {
GenericArgument::Lifetime(_) => {
self.generic_argument(&arg);
self.trailing_comma(arg.is_last);
}
GenericArgument::Type(_)
| GenericArgument::Binding(_)
| GenericArgument::Constraint(_)
| GenericArgument::Const(_) => {}
}
}
for arg in generic.args.iter().delimited() {
match *arg {
GenericArgument::Type(_) | GenericArgument::Const(_) => {
self.generic_argument(&arg);
self.trailing_comma(arg.is_last);
}
GenericArgument::Lifetime(_)
| GenericArgument::Binding(_)
| GenericArgument::Constraint(_) => {}
}
}
for arg in generic.args.iter().delimited() {
match *arg {
GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
self.generic_argument(&arg);
self.trailing_comma(arg.is_last);
}
GenericArgument::Lifetime(_)
| GenericArgument::Type(_)
| GenericArgument::Const(_) => {}
}
}
self.offset(-INDENT);
self.end();
self.word(">");
}
fn binding(&mut self, binding: &Binding) {
self.ident(&binding.ident);
self.word(" = ");
self.ty(&binding.ty);
}
fn constraint(&mut self, constraint: &Constraint) {
self.ident(&constraint.ident);
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<QSelf>, path: &Path) {
let qself = match qself {
Some(qself) => qself,
None => {
self.path(path);
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);
if segment.is_last {
self.word(">");
}
}
} else {
self.word(">");
}
for segment in segments {
self.word("::");
self.path_segment(segment);
}
}
}

View file

@ -1,81 +0,0 @@
use std::collections::VecDeque;
use std::ops::{Index, IndexMut};
pub struct RingBuffer<T> {
data: VecDeque<T>,
// Abstract index of data[0] in infinitely sized queue
offset: usize,
}
impl<T> RingBuffer<T> {
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<T> Index<usize> for RingBuffer<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index.checked_sub(self.offset).unwrap()]
}
}
impl<T> IndexMut<usize> for RingBuffer<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.data[index.checked_sub(self.offset).unwrap()]
}
}

View file

@ -1,85 +0,0 @@
use crate::algorithm::Printer;
use syn::{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((_eq, init)) = &local.init {
self.word(" = ");
self.neverbreak();
self.expr(init);
}
self.word(";");
self.end();
self.hardbreak();
}
Stmt::Item(item) => self.item(item),
Stmt::Expr(expr) => {
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::Semi(expr, _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();
}
}
}
}
pub fn add_semi(expr: &Expr) -> bool {
match expr {
Expr::Assign(_)
| Expr::AssignOp(_)
| Expr::Break(_)
| Expr::Continue(_)
| Expr::Return(_)
| Expr::Yield(_) => true,
Expr::Group(group) => add_semi(&group.expr),
_ => 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,
},
_ => false,
}
}

View file

@ -1,80 +0,0 @@
use crate::algorithm::Printer;
use proc_macro2::{Delimiter, Ident, Literal, Spacing, TokenStream, TokenTree};
impl Printer {
pub fn single_token(&mut self, token: Token, group_contents: fn(&mut Self, TokenStream)) {
match token {
Token::Group(delimiter, stream) => self.token_group(delimiter, stream, group_contents),
Token::Ident(ident) => self.ident(&ident),
Token::Punct(ch, _spacing) => self.token_punct(ch),
Token::Literal(literal) => self.token_literal(&literal),
}
}
fn token_group(
&mut self,
delimiter: Delimiter,
stream: TokenStream,
group_contents: fn(&mut Self, TokenStream),
) {
self.delimiter_open(delimiter);
if !stream.is_empty() {
if delimiter == Delimiter::Brace {
self.space();
}
group_contents(self, stream);
if delimiter == Delimiter::Brace {
self.space();
}
}
self.delimiter_close(delimiter);
}
pub fn ident(&mut self, ident: &Ident) {
self.word(ident.to_string());
}
pub fn token_punct(&mut self, ch: char) {
self.word(ch.to_string());
}
pub fn token_literal(&mut self, literal: &Literal) {
self.word(literal.to_string());
}
pub fn delimiter_open(&mut self, delimiter: Delimiter) {
self.word(match delimiter {
Delimiter::Parenthesis => "(",
Delimiter::Brace => "{",
Delimiter::Bracket => "[",
Delimiter::None => return,
});
}
pub fn delimiter_close(&mut self, delimiter: Delimiter) {
self.word(match delimiter {
Delimiter::Parenthesis => ")",
Delimiter::Brace => "}",
Delimiter::Bracket => "]",
Delimiter::None => return,
});
}
}
pub enum Token {
Group(Delimiter, TokenStream),
Ident(Ident),
Punct(char, Spacing),
Literal(Literal),
}
impl From<TokenTree> 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),
}
}
}

View file

@ -1,232 +0,0 @@
use crate::algorithm::Printer;
use crate::iter::IterDelimited;
use crate::INDENT;
use proc_macro2::TokenStream;
use syn::{
Abi, BareFnArg, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeInfer,
TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject,
TypeTuple, Variadic,
};
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.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) {
self.mac(&ty.mac, None);
}
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);
}
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(feature = "verbatim")]
fn type_verbatim(&mut self, tokens: &TokenStream) {
use syn::parse::{Parse, ParseStream, Result};
use syn::{token, ExprBlock, Lit};
enum TypeVerbatim {
Lit(Lit),
Block(ExprBlock),
}
impl Parse for TypeVerbatim {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Lit) {
input.parse().map(TypeVerbatim::Lit)
} else if lookahead.peek(token::Brace) {
input.parse().map(TypeVerbatim::Block)
} else {
Err(lookahead.error())
}
}
}
let ty: TypeVerbatim = match syn::parse2(tokens.clone()) {
Ok(ty) => ty,
Err(_) => return self.word(tokens.to_string()),
};
match ty {
TypeVerbatim::Lit(lit) => {
self.lit(&lit);
}
TypeVerbatim::Block(block) => {
self.expr_block(&block);
}
}
}
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 variadic(&mut self, variadic: &Variadic) {
self.outer_attrs(&variadic.attrs);
self.word("...");
}
pub fn abi(&mut self, abi: &Abi) {
self.word("extern ");
if let Some(name) = &abi.name {
self.lit_str(name);
self.nbsp();
}
}
}

View file

@ -79,7 +79,7 @@ fn wrap_func_body(func: &str) -> Result<String> {
} }
}; };
Ok(prettyplease::unparse(&syn_file)) crate::formatting::format(syn_file)
} }
impl RustFunction { impl RustFunction {

7
src/formatting.rs Normal file
View file

@ -0,0 +1,7 @@
use std::collections::HashMap;
use genemichaels::FormatConfig;
pub fn format(file: syn::File) -> anyhow::Result<String> {
Ok(genemichaels::format_ast(file, &FormatConfig::default(), HashMap::new())?.rendered)
}

View file

@ -9,6 +9,7 @@ use std::{
mod build; mod build;
mod dylib_flag; mod dylib_flag;
mod formatting;
mod passes; mod passes;
mod processor; mod processor;

View file

@ -196,7 +196,7 @@ impl Minimizer {
match has_made_change { match has_made_change {
ProcessState::Changed | ProcessState::FileInvalidated => { ProcessState::Changed | ProcessState::FileInvalidated => {
let result = prettyplease::unparse(&krate); let result = crate::formatting::format(krate)?;
change.write(&result)?; change.write(&result)?;