Import prettyplease crate

Bug: 274187738
Test: m
Merged-In: I36d5fa8300f210d8489e79c483859769b4bca31c
Change-Id: I36d5fa8300f210d8489e79c483859769b4bca31c
(cherry picked from commit dde97c6839f9cfb46e1d2774d51c177bf92e5780)
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..3e35b72
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "81780e0ebdb1f8df7c36b39a02e606e60581dce9"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..567c199
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+cargo-expand/*.rs linguist-generated
+examples/*.rs linguist-generated
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..7507077
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: dtolnay
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..ca27e6a
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,74 @@
+name: CI
+
+on:
+  push:
+  pull_request:
+  workflow_dispatch:
+  schedule: [cron: "40 1 * * *"]
+
+permissions:
+  contents: read
+
+env:
+  RUSTFLAGS: -Dwarnings
+
+jobs:
+  pre_ci:
+    uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
+
+  test:
+    name: Rust ${{matrix.rust}}
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        rust: [nightly, beta, stable, 1.56.0]
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: ${{matrix.rust}}
+      - run: cargo check
+      - run: cargo check --features verbatim
+      - run: cargo test
+        env:
+          RUSTFLAGS: ${{env.RUSTFLAGS}} ${{matrix.rust == 'nightly' && '--cfg exhaustive' || ''}}
+
+  examples:
+    name: Examples
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          components: llvm-tools, rustc-dev, rustfmt
+      - run: cargo run --manifest-path examples/update/Cargo.toml
+      - run: git diff --exit-code
+      - run: cargo run --manifest-path cargo-expand/update/Cargo.toml
+      - run: git diff --exit-code
+
+  clippy:
+    name: Clippy
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@clippy
+      - run: cargo clippy --features verbatim -- -Dclippy::all -Dclippy::pedantic
+
+  outdated:
+    name: Outdated
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/install@cargo-outdated
+      - run: cargo outdated --workspace --exit-code 1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..96ef6c0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..3e7383d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,20 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+rust_library_host {
+    name: "libprettyplease",
+    crate_name: "prettyplease",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.1.25",
+    srcs: ["src/lib.rs"],
+    edition: "2021",
+    rustlibs: [
+        "libproc_macro2",
+        "libsyn",
+    ],
+    compile_multilib: "first",
+    product_available: true,
+    vendor_available: true,
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e77b675
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,47 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.56"
+name = "prettyplease"
+version = "0.1.25"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+links = "prettyplease01"
+exclude = ["cargo-expand"]
+autoexamples = false
+description = "A minimal `syn` syntax tree pretty-printer"
+documentation = "https://docs.rs/prettyplease"
+readme = "README.md"
+keywords = ["rustfmt"]
+categories = ["development-tools"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/prettyplease"
+
+[lib]
+doc-scrape-examples = false
+
+[dependencies.proc-macro2]
+version = "1.0"
+default-features = false
+
+[dependencies.syn]
+version = "1.0.90"
+features = ["full"]
+default-features = false
+
+[dev-dependencies.syn]
+version = "1.0.90"
+features = ["parsing"]
+default-features = false
+
+[features]
+verbatim = ["syn/parsing"]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..b433848
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "prettyplease"
+description: "A minimal `syn` syntax tree pretty-printer"
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/prettyplease"
+  }
+  url {
+    type: ARCHIVE
+    value: "https://static.crates.io/crates/prettyplease/prettyplease-0.1.25.crate"
+  }
+  version: "0.1.25"
+  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2023
+    month: 3
+    day: 22
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5695972
--- /dev/null
+++ b/README.md
@@ -0,0 +1,312 @@
+prettyplease::unparse
+=====================
+
+[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/prettyplease-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/prettyplease)
+[<img alt="crates.io" src="https://img.shields.io/crates/v/prettyplease.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/prettyplease)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-prettyplease-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/prettyplease)
+[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/prettyplease/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/prettyplease/actions?query=branch%3Amaster)
+
+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:
+
+```rust
+            match segments[5] {
+                0 => write!(f, "::{}", ipv4),
+                0xffff => write!(f, "::ffff:{}", ipv4),
+                _ => unreachable!(),
+            }
+        } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } }
+    } else {
+        const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+        let mut buf = [0u8; IPV6_BUF_LEN];
+        let mut buf_slice = &mut buf[..];
+```
+
+This is a pretty typical manifestation of rustfmt bailing out in generated code
+&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:
+
+```rust
+fn eq(&self, other: &IpAddr) -> bool {
+    match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, }
+}
+```
+
+Some places use non-multiple-of-4 indentation, which is definitely not the norm:
+
+```rust
+pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+    let [a, b, c, d] = self.octets();
+    Ipv6Addr{inner:
+                 c::in6_addr{s6_addr:
+                                 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF,
+                                  0xFF, a, b, c, d],},}
+}
+```
+
+And although there isn't an egregious example of it in the link because the
+input code is pretty tame, in general rustc_ast_pretty has pathological behavior
+on generated code. It has a tendency to use excessive horizontal indentation and
+rapidly run out of width:
+
+```rust
+::std::io::_print(::core::fmt::Arguments::new_v1(&[""],
+                                                 &match (&msg,) {
+                                                      _args =>
+                                                      [::core::fmt::ArgumentV1::new(_args.0,
+                                                                                    ::core::fmt::Display::fmt)],
+                                                  }));
+```
+
+The snippets above are clearly different from modern rustfmt style. In contrast,
+prettyplease is designed to have output that is practically indistinguishable
+from rustfmt-formatted code.
+
+<br>
+
+## Example
+
+```rust
+// [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:
+
+```rust
+let _ = Struct { x: 0, y: true };
+
+let _ = Struct {
+    x: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
+    y: yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,   //<- trailing comma if the expression wrapped
+};
+```
+
+The formatting of `match` expressions is another case; we want small arms on the
+same line as the pattern, and big arms wrapped in a brace. The presence of the
+brace punctuation, comma, and semicolon are all dependent on whether the arm
+fits on the line:
+
+```rust
+match total_nanos.checked_add(entry.nanos as u64) {
+    Some(n) => tmp = n,   //<- small arm, inline with comma
+    None => {
+        total_secs = total_secs
+            .checked_add(total_nanos / NANOS_PER_SEC as u64)
+            .expect("overflow in iter::sum over durations");
+    }   //<- big arm, needs brace added, and also semicolon^
+}
+```
+
+The printing algorithm implementation in this crate accommodates all of these
+situations with conditional punctuation tokens whose selection can be deferred
+and populated after it's known that the group is or is not broken.
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..0d798ed
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,5 @@
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+
+    println!(concat!("cargo:VERSION=", env!("CARGO_PKG_VERSION")));
+}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..c4040f0
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,5 @@
+{
+  "host-first-multilib": true,
+  "run": true,
+  "tests": true
+}
diff --git a/examples/.tokeignore b/examples/.tokeignore
new file mode 100644
index 0000000..6f5f3d1
--- /dev/null
+++ b/examples/.tokeignore
@@ -0,0 +1 @@
+*.rs
diff --git a/examples/input.rs b/examples/input.rs
new file mode 100644
index 0000000..ca3d980
--- /dev/null
+++ b/examples/input.rs
@@ -0,0 +1 @@
+use crate :: cmp :: Ordering ; use crate :: fmt :: { self , Write as FmtWrite } ; use crate :: hash ; use crate :: io :: Write as IoWrite ; use crate :: mem :: transmute ; use crate :: sys :: net :: netc as c ; use crate :: sys_common :: { AsInner , FromInner , IntoInner } ; # [derive (Copy , Clone , Eq , PartialEq , Hash , PartialOrd , Ord)] pub enum IpAddr { V4 (Ipv4Addr) , V6 (Ipv6Addr) , } # [derive (Copy)] pub struct Ipv4Addr { inner : c :: in_addr , } # [derive (Copy)] pub struct Ipv6Addr { inner : c :: in6_addr , } # [derive (Copy , PartialEq , Eq , Clone , Hash , Debug)] # [non_exhaustive] pub enum Ipv6MulticastScope { InterfaceLocal , LinkLocal , RealmLocal , AdminLocal , SiteLocal , OrganizationLocal , Global , } impl IpAddr { pub const fn is_unspecified (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_unspecified () , IpAddr :: V6 (ip) => ip . is_unspecified () , } } pub const fn is_loopback (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_loopback () , IpAddr :: V6 (ip) => ip . is_loopback () , } } pub const fn is_global (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_global () , IpAddr :: V6 (ip) => ip . is_global () , } } pub const fn is_multicast (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_multicast () , IpAddr :: V6 (ip) => ip . is_multicast () , } } pub const fn is_documentation (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_documentation () , IpAddr :: V6 (ip) => ip . is_documentation () , } } pub const fn is_benchmarking (& self) -> bool { match self { IpAddr :: V4 (ip) => ip . is_benchmarking () , IpAddr :: V6 (ip) => ip . is_benchmarking () , } } pub const fn is_ipv4 (& self) -> bool { matches ! (self , IpAddr :: V4 (_)) } pub const fn is_ipv6 (& self) -> bool { matches ! (self , IpAddr :: V6 (_)) } pub const fn to_canonical (& self) -> IpAddr { match self { & v4 @ IpAddr :: V4 (_) => v4 , IpAddr :: V6 (v6) => v6 . to_canonical () , } } } impl Ipv4Addr { pub const fn new (a : u8 , b : u8 , c : u8 , d : u8) -> Ipv4Addr { Ipv4Addr { inner : c :: in_addr { s_addr : u32 :: from_ne_bytes ([a , b , c , d]) } } } pub const LOCALHOST : Self = Ipv4Addr :: new (127 , 0 , 0 , 1) ; # [doc (alias = "INADDR_ANY")] pub const UNSPECIFIED : Self = Ipv4Addr :: new (0 , 0 , 0 , 0) ; pub const BROADCAST : Self = Ipv4Addr :: new (255 , 255 , 255 , 255) ; pub const fn octets (& self) -> [u8 ; 4] { self . inner . s_addr . to_ne_bytes () } pub const fn is_unspecified (& self) -> bool { self . inner . s_addr == 0 } pub const fn is_loopback (& self) -> bool { self . octets () [0] == 127 } pub const fn is_private (& self) -> bool { match self . octets () { [10 , ..] => true , [172 , b , ..] if b >= 16 && b <= 31 => true , [192 , 168 , ..] => true , _ => false , } } pub const fn is_link_local (& self) -> bool { matches ! (self . octets () , [169 , 254 , ..]) } pub const fn is_global (& self) -> bool { if u32 :: from_be_bytes (self . octets ()) == 0xc0000009 || u32 :: from_be_bytes (self . octets ()) == 0xc000000a { return true ; } ! self . is_private () && ! self . is_loopback () && ! self . is_link_local () && ! self . is_broadcast () && ! self . is_documentation () && ! self . is_shared () && ! (self . octets () [0] == 192 && self . octets () [1] == 0 && self . octets () [2] == 0) && ! self . is_reserved () && ! self . is_benchmarking () && self . octets () [0] != 0 } pub const fn is_shared (& self) -> bool { self . octets () [0] == 100 && (self . octets () [1] & 0b1100_0000 == 0b0100_0000) } pub const fn is_benchmarking (& self) -> bool { self . octets () [0] == 198 && (self . octets () [1] & 0xfe) == 18 } pub const fn is_reserved (& self) -> bool { self . octets () [0] & 240 == 240 && ! self . is_broadcast () } pub const fn is_multicast (& self) -> bool { self . octets () [0] >= 224 && self . octets () [0] <= 239 } pub const fn is_broadcast (& self) -> bool { u32 :: from_be_bytes (self . octets ()) == u32 :: from_be_bytes (Self :: BROADCAST . octets ()) } pub const fn is_documentation (& self) -> bool { matches ! (self . octets () , [192 , 0 , 2 , _] | [198 , 51 , 100 , _] | [203 , 0 , 113 , _]) } pub const fn to_ipv6_compatible (& self) -> Ipv6Addr { let [a , b , c , d] = self . octets () ; Ipv6Addr { inner : c :: in6_addr { s6_addr : [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , a , b , c , d] } , } } pub const fn to_ipv6_mapped (& self) -> Ipv6Addr { let [a , b , c , d] = self . octets () ; Ipv6Addr { inner : c :: in6_addr { s6_addr : [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xFF , 0xFF , a , b , c , d] } , } } } impl fmt :: Display for IpAddr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { match self { IpAddr :: V4 (ip) => ip . fmt (fmt) , IpAddr :: V6 (ip) => ip . fmt (fmt) , } } } impl fmt :: Debug for IpAddr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl From < Ipv4Addr > for IpAddr { fn from (ipv4 : Ipv4Addr) -> IpAddr { IpAddr :: V4 (ipv4) } } impl From < Ipv6Addr > for IpAddr { fn from (ipv6 : Ipv6Addr) -> IpAddr { IpAddr :: V6 (ipv6) } } impl fmt :: Display for Ipv4Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { let octets = self . octets () ; if fmt . precision () . is_none () && fmt . width () . is_none () { write ! (fmt , "{}.{}.{}.{}" , octets [0] , octets [1] , octets [2] , octets [3]) } else { const IPV4_BUF_LEN : usize = 15 ; let mut buf = [0u8 ; IPV4_BUF_LEN] ; let mut buf_slice = & mut buf [..] ; write ! (buf_slice , "{}.{}.{}.{}" , octets [0] , octets [1] , octets [2] , octets [3]) . unwrap () ; let len = IPV4_BUF_LEN - buf_slice . len () ; let buf = unsafe { crate :: str :: from_utf8_unchecked (& buf [.. len]) } ; fmt . pad (buf) } } } impl fmt :: Debug for Ipv4Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl Clone for Ipv4Addr { fn clone (& self) -> Ipv4Addr { * self } } impl PartialEq for Ipv4Addr { fn eq (& self , other : & Ipv4Addr) -> bool { self . inner . s_addr == other . inner . s_addr } } impl PartialEq < Ipv4Addr > for IpAddr { fn eq (& self , other : & Ipv4Addr) -> bool { match self { IpAddr :: V4 (v4) => v4 == other , IpAddr :: V6 (_) => false , } } } impl PartialEq < IpAddr > for Ipv4Addr { fn eq (& self , other : & IpAddr) -> bool { match other { IpAddr :: V4 (v4) => self == v4 , IpAddr :: V6 (_) => false , } } } impl Eq for Ipv4Addr { } impl hash :: Hash for Ipv4Addr { fn hash < H : hash :: Hasher > (& self , s : & mut H) { { self . inner . s_addr } . hash (s) } } impl PartialOrd for Ipv4Addr { fn partial_cmp (& self , other : & Ipv4Addr) -> Option < Ordering > { Some (self . cmp (other)) } } impl PartialOrd < Ipv4Addr > for IpAddr { fn partial_cmp (& self , other : & Ipv4Addr) -> Option < Ordering > { match self { IpAddr :: V4 (v4) => v4 . partial_cmp (other) , IpAddr :: V6 (_) => Some (Ordering :: Greater) , } } } impl PartialOrd < IpAddr > for Ipv4Addr { fn partial_cmp (& self , other : & IpAddr) -> Option < Ordering > { match other { IpAddr :: V4 (v4) => self . partial_cmp (v4) , IpAddr :: V6 (_) => Some (Ordering :: Less) , } } } impl Ord for Ipv4Addr { fn cmp (& self , other : & Ipv4Addr) -> Ordering { u32 :: from_be (self . inner . s_addr) . cmp (& u32 :: from_be (other . inner . s_addr)) } } impl IntoInner < c :: in_addr > for Ipv4Addr { fn into_inner (self) -> c :: in_addr { self . inner } } impl From < Ipv4Addr > for u32 { fn from (ip : Ipv4Addr) -> u32 { let ip = ip . octets () ; u32 :: from_be_bytes (ip) } } impl From < u32 > for Ipv4Addr { fn from (ip : u32) -> Ipv4Addr { Ipv4Addr :: from (ip . to_be_bytes ()) } } impl From < [u8 ; 4] > for Ipv4Addr { fn from (octets : [u8 ; 4]) -> Ipv4Addr { Ipv4Addr :: new (octets [0] , octets [1] , octets [2] , octets [3]) } } impl From < [u8 ; 4] > for IpAddr { fn from (octets : [u8 ; 4]) -> IpAddr { IpAddr :: V4 (Ipv4Addr :: from (octets)) } } impl Ipv6Addr { pub const fn new (a : u16 , b : u16 , c : u16 , d : u16 , e : u16 , f : u16 , g : u16 , h : u16) -> Ipv6Addr { let addr16 = [a . to_be () , b . to_be () , c . to_be () , d . to_be () , e . to_be () , f . to_be () , g . to_be () , h . to_be () ,] ; Ipv6Addr { inner : c :: in6_addr { s6_addr : unsafe { transmute :: < _ , [u8 ; 16] > (addr16) } , } , } } pub const LOCALHOST : Self = Ipv6Addr :: new (0 , 0 , 0 , 0 , 0 , 0 , 0 , 1) ; pub const UNSPECIFIED : Self = Ipv6Addr :: new (0 , 0 , 0 , 0 , 0 , 0 , 0 , 0) ; pub const fn segments (& self) -> [u16 ; 8] { let [a , b , c , d , e , f , g , h] = unsafe { transmute :: < _ , [u16 ; 8] > (self . inner . s6_addr) } ; [u16 :: from_be (a) , u16 :: from_be (b) , u16 :: from_be (c) , u16 :: from_be (d) , u16 :: from_be (e) , u16 :: from_be (f) , u16 :: from_be (g) , u16 :: from_be (h) ,] } pub const fn is_unspecified (& self) -> bool { u128 :: from_be_bytes (self . octets ()) == u128 :: from_be_bytes (Ipv6Addr :: UNSPECIFIED . octets ()) } pub const fn is_loopback (& self) -> bool { u128 :: from_be_bytes (self . octets ()) == u128 :: from_be_bytes (Ipv6Addr :: LOCALHOST . octets ()) } pub const fn is_global (& self) -> bool { match self . multicast_scope () { Some (Ipv6MulticastScope :: Global) => true , None => self . is_unicast_global () , _ => false , } } pub const fn is_unique_local (& self) -> bool { (self . segments () [0] & 0xfe00) == 0xfc00 } pub const fn is_unicast (& self) -> bool { ! self . is_multicast () } pub const fn is_unicast_link_local (& self) -> bool { (self . segments () [0] & 0xffc0) == 0xfe80 } pub const fn is_documentation (& self) -> bool { (self . segments () [0] == 0x2001) && (self . segments () [1] == 0xdb8) } pub const fn is_benchmarking (& self) -> bool { (self . segments () [0] == 0x2001) && (self . segments () [1] == 0x2) && (self . segments () [2] == 0) } pub const fn is_unicast_global (& self) -> bool { self . is_unicast () && ! self . is_loopback () && ! self . is_unicast_link_local () && ! self . is_unique_local () && ! self . is_unspecified () && ! self . is_documentation () } pub const fn multicast_scope (& self) -> Option < Ipv6MulticastScope > { if self . is_multicast () { match self . segments () [0] & 0x000f { 1 => Some (Ipv6MulticastScope :: InterfaceLocal) , 2 => Some (Ipv6MulticastScope :: LinkLocal) , 3 => Some (Ipv6MulticastScope :: RealmLocal) , 4 => Some (Ipv6MulticastScope :: AdminLocal) , 5 => Some (Ipv6MulticastScope :: SiteLocal) , 8 => Some (Ipv6MulticastScope :: OrganizationLocal) , 14 => Some (Ipv6MulticastScope :: Global) , _ => None , } } else { None } } pub const fn is_multicast (& self) -> bool { (self . segments () [0] & 0xff00) == 0xff00 } pub const fn to_ipv4_mapped (& self) -> Option < Ipv4Addr > { match self . octets () { [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0xff , a , b , c , d] => { Some (Ipv4Addr :: new (a , b , c , d)) } _ => None , } } pub const fn to_ipv4 (& self) -> Option < Ipv4Addr > { if let [0 , 0 , 0 , 0 , 0 , 0 | 0xffff , ab , cd] = self . segments () { let [a , b] = ab . to_be_bytes () ; let [c , d] = cd . to_be_bytes () ; Some (Ipv4Addr :: new (a , b , c , d)) } else { None } } pub const fn to_canonical (& self) -> IpAddr { if let Some (mapped) = self . to_ipv4_mapped () { return IpAddr :: V4 (mapped) ; } IpAddr :: V6 (* self) } pub const fn octets (& self) -> [u8 ; 16] { self . inner . s6_addr } } impl fmt :: Display for Ipv6Addr { fn fmt (& self , f : & mut fmt :: Formatter < '_ >) -> fmt :: Result { if f . precision () . is_none () && f . width () . is_none () { let segments = self . segments () ; if self . is_unspecified () { f . write_str ("::") } else if self . is_loopback () { f . write_str ("::1") } else if let Some (ipv4) = self . to_ipv4 () { match segments [5] { 0 => write ! (f , "::{}" , ipv4) , 0xffff => write ! (f , "::ffff:{}" , ipv4) , _ => unreachable ! () , } } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } } } else { const IPV6_BUF_LEN : usize = (4 * 8) + 7 ; let mut buf = [0u8 ; IPV6_BUF_LEN] ; let mut buf_slice = & mut buf [..] ; write ! (buf_slice , "{}" , self) . unwrap () ; let len = IPV6_BUF_LEN - buf_slice . len () ; let buf = unsafe { crate :: str :: from_utf8_unchecked (& buf [.. len]) } ; f . pad (buf) } } } impl fmt :: Debug for Ipv6Addr { fn fmt (& self , fmt : & mut fmt :: Formatter < '_ >) -> fmt :: Result { fmt :: Display :: fmt (self , fmt) } } impl Clone for Ipv6Addr { fn clone (& self) -> Ipv6Addr { * self } } impl PartialEq for Ipv6Addr { fn eq (& self , other : & Ipv6Addr) -> bool { self . inner . s6_addr == other . inner . s6_addr } } impl PartialEq < IpAddr > for Ipv6Addr { fn eq (& self , other : & IpAddr) -> bool { match other { IpAddr :: V4 (_) => false , IpAddr :: V6 (v6) => self == v6 , } } } impl PartialEq < Ipv6Addr > for IpAddr { fn eq (& self , other : & Ipv6Addr) -> bool { match self { IpAddr :: V4 (_) => false , IpAddr :: V6 (v6) => v6 == other , } } } impl Eq for Ipv6Addr { } impl hash :: Hash for Ipv6Addr { fn hash < H : hash :: Hasher > (& self , s : & mut H) { self . inner . s6_addr . hash (s) } } impl PartialOrd for Ipv6Addr { fn partial_cmp (& self , other : & Ipv6Addr) -> Option < Ordering > { Some (self . cmp (other)) } } impl PartialOrd < Ipv6Addr > for IpAddr { fn partial_cmp (& self , other : & Ipv6Addr) -> Option < Ordering > { match self { IpAddr :: V4 (_) => Some (Ordering :: Less) , IpAddr :: V6 (v6) => v6 . partial_cmp (other) , } } } impl PartialOrd < IpAddr > for Ipv6Addr { fn partial_cmp (& self , other : & IpAddr) -> Option < Ordering > { match other { IpAddr :: V4 (_) => Some (Ordering :: Greater) , IpAddr :: V6 (v6) => self . partial_cmp (v6) , } } } impl Ord for Ipv6Addr { fn cmp (& self , other : & Ipv6Addr) -> Ordering { self . segments () . cmp (& other . segments ()) } } impl AsInner < c :: in6_addr > for Ipv6Addr { fn as_inner (& self) -> & c :: in6_addr { & self . inner } } impl FromInner < c :: in6_addr > for Ipv6Addr { fn from_inner (addr : c :: in6_addr) -> Ipv6Addr { Ipv6Addr { inner : addr } } } impl From < Ipv6Addr > for u128 { fn from (ip : Ipv6Addr) -> u128 { let ip = ip . octets () ; u128 :: from_be_bytes (ip) } } impl From < u128 > for Ipv6Addr { fn from (ip : u128) -> Ipv6Addr { Ipv6Addr :: from (ip . to_be_bytes ()) } } impl From < [u8 ; 16] > for Ipv6Addr { fn from (octets : [u8 ; 16]) -> Ipv6Addr { let inner = c :: in6_addr { s6_addr : octets } ; Ipv6Addr :: from_inner (inner) } } impl From < [u16 ; 8] > for Ipv6Addr { fn from (segments : [u16 ; 8]) -> Ipv6Addr { let [a , b , c , d , e , f , g , h] = segments ; Ipv6Addr :: new (a , b , c , d , e , f , g , h) } } impl From < [u8 ; 16] > for IpAddr { fn from (octets : [u8 ; 16]) -> IpAddr { IpAddr :: V6 (Ipv6Addr :: from (octets)) } } impl From < [u16 ; 8] > for IpAddr { fn from (segments : [u16 ; 8]) -> IpAddr { IpAddr :: V6 (Ipv6Addr :: from (segments)) } }
diff --git a/examples/output.prettyplease.rs b/examples/output.prettyplease.rs
new file mode 100644
index 0000000..45b65d0
--- /dev/null
+++ b/examples/output.prettyplease.rs
@@ -0,0 +1,593 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write as FmtWrite};
+use crate::hash;
+use crate::io::Write as IoWrite;
+use crate::mem::transmute;
+use crate::sys::net::netc as c;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+    V4(Ipv4Addr),
+    V6(Ipv6Addr),
+}
+#[derive(Copy)]
+pub struct Ipv4Addr {
+    inner: c::in_addr,
+}
+#[derive(Copy)]
+pub struct Ipv6Addr {
+    inner: c::in6_addr,
+}
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[non_exhaustive]
+pub enum Ipv6MulticastScope {
+    InterfaceLocal,
+    LinkLocal,
+    RealmLocal,
+    AdminLocal,
+    SiteLocal,
+    OrganizationLocal,
+    Global,
+}
+impl IpAddr {
+    pub const fn is_unspecified(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_unspecified(),
+            IpAddr::V6(ip) => ip.is_unspecified(),
+        }
+    }
+    pub const fn is_loopback(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_loopback(),
+            IpAddr::V6(ip) => ip.is_loopback(),
+        }
+    }
+    pub const fn is_global(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_global(),
+            IpAddr::V6(ip) => ip.is_global(),
+        }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_multicast(),
+            IpAddr::V6(ip) => ip.is_multicast(),
+        }
+    }
+    pub const fn is_documentation(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_documentation(),
+            IpAddr::V6(ip) => ip.is_documentation(),
+        }
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_benchmarking(),
+            IpAddr::V6(ip) => ip.is_benchmarking(),
+        }
+    }
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(self, IpAddr::V4(_))
+    }
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(self, IpAddr::V6(_))
+    }
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
+}
+impl Ipv4Addr {
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr {
+            inner: c::in_addr {
+                s_addr: u32::from_ne_bytes([a, b, c, d]),
+            },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+    #[doc(alias = "INADDR_ANY")]
+    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+    pub const fn octets(&self) -> [u8; 4] {
+        self.inner.s_addr.to_ne_bytes()
+    }
+    pub const fn is_unspecified(&self) -> bool {
+        self.inner.s_addr == 0
+    }
+    pub const fn is_loopback(&self) -> bool {
+        self.octets()[0] == 127
+    }
+    pub const fn is_private(&self) -> bool {
+        match self.octets() {
+            [10, ..] => true,
+            [172, b, ..] if b >= 16 && b <= 31 => true,
+            [192, 168, ..] => true,
+            _ => false,
+        }
+    }
+    pub const fn is_link_local(&self) -> bool {
+        matches!(self.octets(), [169, 254, ..])
+    }
+    pub const fn is_global(&self) -> bool {
+        if u32::from_be_bytes(self.octets()) == 0xc0000009
+            || u32::from_be_bytes(self.octets()) == 0xc000000a
+        {
+            return true;
+        }
+        !self.is_private() && !self.is_loopback() && !self.is_link_local()
+            && !self.is_broadcast() && !self.is_documentation() && !self.is_shared()
+            && !(self.octets()[0] == 192 && self.octets()[1] == 0
+                && self.octets()[2] == 0) && !self.is_reserved()
+            && !self.is_benchmarking() && self.octets()[0] != 0
+    }
+    pub const fn is_shared(&self) -> bool {
+        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+    }
+    pub const fn is_reserved(&self) -> bool {
+        self.octets()[0] & 240 == 240 && !self.is_broadcast()
+    }
+    pub const fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+    pub const fn is_broadcast(&self) -> bool {
+        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
+    }
+    pub const fn is_documentation(&self) -> bool {
+        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
+    }
+    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d],
+            },
+        }
+    }
+    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d],
+            },
+        }
+    }
+}
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            IpAddr::V4(ip) => ip.fmt(fmt),
+            IpAddr::V6(ip) => ip.fmt(fmt),
+        }
+    }
+}
+impl fmt::Debug for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl From<Ipv4Addr> for IpAddr {
+    fn from(ipv4: Ipv4Addr) -> IpAddr {
+        IpAddr::V4(ipv4)
+    }
+}
+impl From<Ipv6Addr> for IpAddr {
+    fn from(ipv6: Ipv6Addr) -> IpAddr {
+        IpAddr::V6(ipv6)
+    }
+}
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let octets = self.octets();
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+        } else {
+            const IPV4_BUF_LEN: usize = 15;
+            let mut buf = [0u8; IPV4_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+            write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+                .unwrap();
+            let len = IPV4_BUF_LEN - buf_slice.len();
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            fmt.pad(buf)
+        }
+    }
+}
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv4Addr {
+    fn clone(&self) -> Ipv4Addr {
+        *self
+    }
+}
+impl PartialEq for Ipv4Addr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.inner.s_addr == other.inner.s_addr
+    }
+}
+impl PartialEq<Ipv4Addr> for IpAddr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        match self {
+            IpAddr::V4(v4) => v4 == other,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+impl PartialEq<IpAddr> for Ipv4Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(v4) => self == v4,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+impl Eq for Ipv4Addr {}
+impl hash::Hash for Ipv4Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        { self.inner.s_addr }.hash(s)
+    }
+}
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv4Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(v4) => v4.partial_cmp(other),
+            IpAddr::V6(_) => Some(Ordering::Greater),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv4Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(v4) => self.partial_cmp(v4),
+            IpAddr::V6(_) => Some(Ordering::Less),
+        }
+    }
+}
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
+    }
+}
+impl IntoInner<c::in_addr> for Ipv4Addr {
+    fn into_inner(self) -> c::in_addr {
+        self.inner
+    }
+}
+impl From<Ipv4Addr> for u32 {
+    fn from(ip: Ipv4Addr) -> u32 {
+        let ip = ip.octets();
+        u32::from_be_bytes(ip)
+    }
+}
+impl From<u32> for Ipv4Addr {
+    fn from(ip: u32) -> Ipv4Addr {
+        Ipv4Addr::from(ip.to_be_bytes())
+    }
+}
+impl From<[u8; 4]> for Ipv4Addr {
+    fn from(octets: [u8; 4]) -> Ipv4Addr {
+        Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
+    }
+}
+impl From<[u8; 4]> for IpAddr {
+    fn from(octets: [u8; 4]) -> IpAddr {
+        IpAddr::V4(Ipv4Addr::from(octets))
+    }
+}
+impl Ipv6Addr {
+    pub const fn new(
+        a: u16,
+        b: u16,
+        c: u16,
+        d: u16,
+        e: u16,
+        f: u16,
+        g: u16,
+        h: u16,
+    ) -> Ipv6Addr {
+        let addr16 = [
+            a.to_be(),
+            b.to_be(),
+            c.to_be(),
+            d.to_be(),
+            e.to_be(),
+            f.to_be(),
+            g.to_be(),
+            h.to_be(),
+        ];
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
+            },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    pub const fn segments(&self) -> [u16; 8] {
+        let [a, b, c, d, e, f, g, h] = unsafe {
+            transmute::<_, [u16; 8]>(self.inner.s6_addr)
+        };
+        [
+            u16::from_be(a),
+            u16::from_be(b),
+            u16::from_be(c),
+            u16::from_be(d),
+            u16::from_be(e),
+            u16::from_be(f),
+            u16::from_be(g),
+            u16::from_be(h),
+        ]
+    }
+    pub const fn is_unspecified(&self) -> bool {
+        u128::from_be_bytes(self.octets())
+            == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
+    }
+    pub const fn is_loopback(&self) -> bool {
+        u128::from_be_bytes(self.octets())
+            == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
+    }
+    pub const fn is_global(&self) -> bool {
+        match self.multicast_scope() {
+            Some(Ipv6MulticastScope::Global) => true,
+            None => self.is_unicast_global(),
+            _ => false,
+        }
+    }
+    pub const fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+    pub const fn is_unicast(&self) -> bool {
+        !self.is_multicast()
+    }
+    pub const fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+    pub const fn is_documentation(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2)
+            && (self.segments()[2] == 0)
+    }
+    pub const fn is_unicast_global(&self) -> bool {
+        self.is_unicast() && !self.is_loopback() && !self.is_unicast_link_local()
+            && !self.is_unique_local() && !self.is_unspecified()
+            && !self.is_documentation()
+    }
+    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+            match self.segments()[0] & 0x000f {
+                1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                2 => Some(Ipv6MulticastScope::LinkLocal),
+                3 => Some(Ipv6MulticastScope::RealmLocal),
+                4 => Some(Ipv6MulticastScope::AdminLocal),
+                5 => Some(Ipv6MulticastScope::SiteLocal),
+                8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                14 => Some(Ipv6MulticastScope::Global),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
+        match self.octets() {
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
+                Some(Ipv4Addr::new(a, b, c, d))
+            }
+            _ => None,
+        }
+    }
+    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
+            let [a, b] = ab.to_be_bytes();
+            let [c, d] = cd.to_be_bytes();
+            Some(Ipv4Addr::new(a, b, c, d))
+        } else {
+            None
+        }
+    }
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+    pub const fn octets(&self) -> [u8; 16] {
+        self.inner.s6_addr
+    }
+}
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    0 => write!(f, "::{}", ipv4),
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else {
+                #[derive(Copy, Clone, Default)]
+                struct Span {
+                    start: usize,
+                    len: usize,
+                }
+                let zeroes = {
+                    let mut longest = Span::default();
+                    let mut current = Span::default();
+                    for (i, &segment) in segments.iter().enumerate() {
+                        if segment == 0 {
+                            if current.len == 0 {
+                                current.start = i;
+                            }
+                            current.len += 1;
+                            if current.len > longest.len {
+                                longest = current;
+                            }
+                        } else {
+                            current = Span::default();
+                        }
+                    }
+                    longest
+                };
+                /// Write a colon-separated part of the address
+                #[inline]
+                fn fmt_subslice(
+                    f: &mut fmt::Formatter<'_>,
+                    chunk: &[u16],
+                ) -> fmt::Result {
+                    if let Some((first, tail)) = chunk.split_first() {
+                        write!(f, "{:x}", first)?;
+                        for segment in tail {
+                            f.write_char(':')?;
+                            write!(f, "{:x}", segment)?;
+                        }
+                    }
+                    Ok(())
+                }
+                if zeroes.len > 1 {
+                    fmt_subslice(f, &segments[..zeroes.start])?;
+                    f.write_str("::")?;
+                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
+                } else {
+                    fmt_subslice(f, &segments)
+                }
+            }
+        } else {
+            const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+            let mut buf = [0u8; IPV6_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+            write!(buf_slice, "{}", self).unwrap();
+            let len = IPV6_BUF_LEN - buf_slice.len();
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
+        }
+    }
+}
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv6Addr {
+    fn clone(&self) -> Ipv6Addr {
+        *self
+    }
+}
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        self.inner.s6_addr == other.inner.s6_addr
+    }
+}
+impl PartialEq<IpAddr> for Ipv6Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => self == v6,
+        }
+    }
+}
+impl PartialEq<Ipv6Addr> for IpAddr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        match self {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => v6 == other,
+        }
+    }
+}
+impl Eq for Ipv6Addr {}
+impl hash::Hash for Ipv6Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        self.inner.s6_addr.hash(s)
+    }
+}
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv6Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(_) => Some(Ordering::Less),
+            IpAddr::V6(v6) => v6.partial_cmp(other),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv6Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(_) => Some(Ordering::Greater),
+            IpAddr::V6(v6) => self.partial_cmp(v6),
+        }
+    }
+}
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.segments().cmp(&other.segments())
+    }
+}
+impl AsInner<c::in6_addr> for Ipv6Addr {
+    fn as_inner(&self) -> &c::in6_addr {
+        &self.inner
+    }
+}
+impl FromInner<c::in6_addr> for Ipv6Addr {
+    fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
+        Ipv6Addr { inner: addr }
+    }
+}
+impl From<Ipv6Addr> for u128 {
+    fn from(ip: Ipv6Addr) -> u128 {
+        let ip = ip.octets();
+        u128::from_be_bytes(ip)
+    }
+}
+impl From<u128> for Ipv6Addr {
+    fn from(ip: u128) -> Ipv6Addr {
+        Ipv6Addr::from(ip.to_be_bytes())
+    }
+}
+impl From<[u8; 16]> for Ipv6Addr {
+    fn from(octets: [u8; 16]) -> Ipv6Addr {
+        let inner = c::in6_addr { s6_addr: octets };
+        Ipv6Addr::from_inner(inner)
+    }
+}
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+impl From<[u8; 16]> for IpAddr {
+    fn from(octets: [u8; 16]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(octets))
+    }
+}
+impl From<[u16; 8]> for IpAddr {
+    fn from(segments: [u16; 8]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(segments))
+    }
+}
diff --git a/examples/output.rustc.rs b/examples/output.rustc.rs
new file mode 100644
index 0000000..609a8c3
--- /dev/null
+++ b/examples/output.rustc.rs
@@ -0,0 +1,508 @@
+use crate::cmp::Ordering;use crate::fmt::{self, Write as FmtWrite};
+use crate::hash;
+use crate::io::Write as IoWrite;
+use crate::mem::transmute;
+use crate::sys::net::netc as c;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), }
+#[derive(Copy)]
+pub struct Ipv4Addr {
+    inner: c::in_addr,
+}
+#[derive(Copy)]
+pub struct Ipv6Addr {
+    inner: c::in6_addr,
+}
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[non_exhaustive]
+pub enum Ipv6MulticastScope {
+    InterfaceLocal,
+    LinkLocal,
+    RealmLocal,
+    AdminLocal,
+    SiteLocal,
+    OrganizationLocal,
+    Global,
+}
+impl IpAddr {
+    pub const fn is_unspecified(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_unspecified(),
+            IpAddr::V6(ip) => ip.is_unspecified(),
+        }
+    }
+    pub const fn is_loopback(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_loopback(),
+            IpAddr::V6(ip) => ip.is_loopback(),
+        }
+    }
+    pub const fn is_global(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_global(),
+            IpAddr::V6(ip) => ip.is_global(),
+        }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_multicast(),
+            IpAddr::V6(ip) => ip.is_multicast(),
+        }
+    }
+    pub const fn is_documentation(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_documentation(),
+            IpAddr::V6(ip) => ip.is_documentation(),
+        }
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_benchmarking(),
+            IpAddr::V6(ip) => ip.is_benchmarking(),
+        }
+    }
+    pub const fn is_ipv4(&self) -> bool { matches!(self, IpAddr :: V4(_)) }
+    pub const fn is_ipv6(&self) -> bool { matches!(self, IpAddr :: V6(_)) }
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
+}
+impl Ipv4Addr {
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr {
+            inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+    #[doc(alias = "INADDR_ANY")]
+    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+    pub const fn octets(&self) -> [u8; 4] { self.inner.s_addr.to_ne_bytes() }
+    pub const fn is_unspecified(&self) -> bool { self.inner.s_addr == 0 }
+    pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 }
+    pub const fn is_private(&self) -> bool {
+        match self.octets() {
+            [10, ..] => true,
+            [172, b, ..] if b >= 16 && b <= 31 => true,
+            [192, 168, ..] => true,
+            _ => false,
+        }
+    }
+    pub const fn is_link_local(&self) -> bool {
+        matches!(self.octets(), [169, 254, ..])
+    }
+    pub const fn is_global(&self) -> bool {
+        if u32::from_be_bytes(self.octets()) == 0xc0000009 ||
+                    u32::from_be_bytes(self.octets()) == 0xc000000a {
+                return true;
+            }
+        !self.is_private() && !self.is_loopback() && !self.is_link_local() &&
+                                    !self.is_broadcast() && !self.is_documentation() &&
+                            !self.is_shared() &&
+                        !(self.octets()[0] == 192 && self.octets()[1] == 0 &&
+                                    self.octets()[2] == 0) && !self.is_reserved() &&
+                !self.is_benchmarking() && self.octets()[0] != 0
+    }
+    pub const fn is_shared(&self) -> bool {
+        self.octets()[0] == 100 &&
+            (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+    }
+    pub const fn is_reserved(&self) -> bool {
+        self.octets()[0] & 240 == 240 && !self.is_broadcast()
+    }
+    pub const fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+    pub const fn is_broadcast(&self) -> bool {
+        u32::from_be_bytes(self.octets()) ==
+            u32::from_be_bytes(Self::BROADCAST.octets())
+    }
+    pub const fn is_documentation(&self) -> bool {
+        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] |
+            [203, 0, 113, _])
+    }
+    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d],
+            },
+        }
+    }
+    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c,
+                        d],
+            },
+        }
+    }
+}
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            IpAddr::V4(ip) => ip.fmt(fmt),
+            IpAddr::V6(ip) => ip.fmt(fmt),
+        }
+    }
+}
+impl fmt::Debug for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl From<Ipv4Addr> for IpAddr {
+    fn from(ipv4: Ipv4Addr) -> IpAddr { IpAddr::V4(ipv4) }
+}
+impl From<Ipv6Addr> for IpAddr {
+    fn from(ipv6: Ipv6Addr) -> IpAddr { IpAddr::V6(ipv6) }
+}
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let octets = self.octets();
+        if fmt.precision().is_none() && fmt.width().is_none() {
+                write!(fmt, "{}.{}.{}.{}", octets [0], octets [1], octets [2],
+                    octets [3])
+            } else {
+               const IPV4_BUF_LEN: usize = 15;
+               let mut buf = [0u8; IPV4_BUF_LEN];
+               let mut buf_slice = &mut buf[..];
+               write!(buf_slice, "{}.{}.{}.{}", octets [0], octets [1], octets
+                       [2], octets [3]).unwrap();
+               let len = IPV4_BUF_LEN - buf_slice.len();
+               let buf =
+                   unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+               fmt.pad(buf)
+           }
+    }
+}
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv4Addr {
+    fn clone(&self) -> Ipv4Addr { *self }
+}
+impl PartialEq for Ipv4Addr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.inner.s_addr == other.inner.s_addr
+    }
+}
+impl PartialEq<Ipv4Addr> for IpAddr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        match self { IpAddr::V4(v4) => v4 == other, IpAddr::V6(_) => false, }
+    }
+}
+impl PartialEq<IpAddr> for Ipv4Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other { IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, }
+    }
+}
+impl Eq for Ipv4Addr {}
+impl hash::Hash for Ipv4Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        { self.inner.s_addr }.hash(s)
+    }
+}
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv4Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(v4) => v4.partial_cmp(other),
+            IpAddr::V6(_) => Some(Ordering::Greater),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv4Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(v4) => self.partial_cmp(v4),
+            IpAddr::V6(_) => Some(Ordering::Less),
+        }
+    }
+}
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
+    }
+}
+impl IntoInner<c::in_addr> for Ipv4Addr {
+    fn into_inner(self) -> c::in_addr { self.inner }
+}
+impl From<Ipv4Addr> for u32 {
+    fn from(ip: Ipv4Addr) -> u32 {
+        let ip = ip.octets();
+        u32::from_be_bytes(ip)
+    }
+}
+impl From<u32> for Ipv4Addr {
+    fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::from(ip.to_be_bytes()) }
+}
+impl From<[u8; 4]> for Ipv4Addr {
+    fn from(octets: [u8; 4]) -> Ipv4Addr {
+        Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
+    }
+}
+impl From<[u8; 4]> for IpAddr {
+    fn from(octets: [u8; 4]) -> IpAddr { IpAddr::V4(Ipv4Addr::from(octets)) }
+}
+impl Ipv6Addr {
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
+        h: u16) -> Ipv6Addr {
+        let addr16 =
+            [a.to_be(), b.to_be(), c.to_be(), d.to_be(), e.to_be(), f.to_be(),
+                    g.to_be(), h.to_be()];
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
+            },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    pub const fn segments(&self) -> [u16; 8] {
+        let [a, b, c, d, e, f, g, h] =
+            unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
+        [u16::from_be(a), u16::from_be(b), u16::from_be(c), u16::from_be(d),
+                u16::from_be(e), u16::from_be(f), u16::from_be(g),
+                u16::from_be(h)]
+    }
+    pub const fn is_unspecified(&self) -> bool {
+        u128::from_be_bytes(self.octets()) ==
+            u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
+    }
+    pub const fn is_loopback(&self) -> bool {
+        u128::from_be_bytes(self.octets()) ==
+            u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
+    }
+    pub const fn is_global(&self) -> bool {
+        match self.multicast_scope() {
+            Some(Ipv6MulticastScope::Global) => true,
+            None => self.is_unicast_global(),
+            _ => false,
+        }
+    }
+    pub const fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+    pub const fn is_unicast(&self) -> bool { !self.is_multicast() }
+    pub const fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+    pub const fn is_documentation(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) &&
+            (self.segments()[2] == 0)
+    }
+    pub const fn is_unicast_global(&self) -> bool {
+        self.is_unicast() && !self.is_loopback() &&
+                        !self.is_unicast_link_local() && !self.is_unique_local() &&
+                !self.is_unspecified() && !self.is_documentation()
+    }
+    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+                match self.segments()[0] & 0x000f {
+                    1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                    2 => Some(Ipv6MulticastScope::LinkLocal),
+                    3 => Some(Ipv6MulticastScope::RealmLocal),
+                    4 => Some(Ipv6MulticastScope::AdminLocal),
+                    5 => Some(Ipv6MulticastScope::SiteLocal),
+                    8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                    14 => Some(Ipv6MulticastScope::Global),
+                    _ => None,
+                }
+            } else { None }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
+        match self.octets() {
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
+                Some(Ipv4Addr::new(a, b, c, d))
+            }
+            _ => None,
+        }
+    }
+    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
+                let [a, b] = ab.to_be_bytes();
+                let [c, d] = cd.to_be_bytes();
+                Some(Ipv4Addr::new(a, b, c, d))
+            } else { None }
+    }
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+                return IpAddr::V4(mapped);
+            }
+        IpAddr::V6(*self)
+    }
+    pub const fn octets(&self) -> [u8; 16] { self.inner.s6_addr }
+}
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if f.precision().is_none() && f.width().is_none() {
+                let segments = self.segments();
+                if self.is_unspecified() {
+                        f.write_str("::")
+                    } else if self.is_loopback() {
+                       f.write_str("::1")
+                   } else if let Some(ipv4) = self.to_ipv4() {
+                       match segments[5] {
+                           0 => write!(f, "::{}", ipv4),
+                           0xffff => write!(f, "::ffff:{}", ipv4),
+                           _ => unreachable!(),
+                       }
+                   } else {
+                       #[derive(Copy, Clone, Default)]
+                       struct Span {
+                           start: usize,
+                           len: usize,
+                       }
+                       let zeroes =
+                           {
+                               let mut longest = Span::default();
+                               let mut current = Span::default();
+                               for (i, &segment) in segments.iter().enumerate() {
+                                   if segment == 0 {
+                                           if current.len == 0 { current.start = i; }
+                                           current.len += 1;
+                                           if current.len > longest.len { longest = current; }
+                                       } else { current = Span::default(); }
+                               }
+                               longest
+                           };
+                       #[doc = " Write a colon-separated part of the address"]
+                       #[inline]
+                       fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16])
+                           -> fmt::Result {
+                           if let Some((first, tail)) = chunk.split_first() {
+                                   write!(f, "{:x}", first)?;
+                                   for segment in tail {
+                                       f.write_char(':')?;
+                                       write!(f, "{:x}", segment)?;
+                                   }
+                               }
+                           Ok(())
+                       }
+                       if zeroes.len > 1 {
+                               fmt_subslice(f, &segments[..zeroes.start])?;
+                               f.write_str("::")?;
+                               fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
+                           } else { fmt_subslice(f, &segments) }
+                   }
+            } else {
+               const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+               let mut buf = [0u8; IPV6_BUF_LEN];
+               let mut buf_slice = &mut buf[..];
+               write!(buf_slice, "{}", self).unwrap();
+               let len = IPV6_BUF_LEN - buf_slice.len();
+               let buf =
+                   unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+               f.pad(buf)
+           }
+    }
+}
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv6Addr {
+    fn clone(&self) -> Ipv6Addr { *self }
+}
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        self.inner.s6_addr == other.inner.s6_addr
+    }
+}
+impl PartialEq<IpAddr> for Ipv6Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other { IpAddr::V4(_) => false, IpAddr::V6(v6) => self == v6, }
+    }
+}
+impl PartialEq<Ipv6Addr> for IpAddr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        match self { IpAddr::V4(_) => false, IpAddr::V6(v6) => v6 == other, }
+    }
+}
+impl Eq for Ipv6Addr {}
+impl hash::Hash for Ipv6Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) { self.inner.s6_addr.hash(s) }
+}
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv6Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(_) => Some(Ordering::Less),
+            IpAddr::V6(v6) => v6.partial_cmp(other),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv6Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(_) => Some(Ordering::Greater),
+            IpAddr::V6(v6) => self.partial_cmp(v6),
+        }
+    }
+}
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.segments().cmp(&other.segments())
+    }
+}
+impl AsInner<c::in6_addr> for Ipv6Addr {
+    fn as_inner(&self) -> &c::in6_addr { &self.inner }
+}
+impl FromInner<c::in6_addr> for Ipv6Addr {
+    fn from_inner(addr: c::in6_addr) -> Ipv6Addr { Ipv6Addr { inner: addr } }
+}
+impl From<Ipv6Addr> for u128 {
+    fn from(ip: Ipv6Addr) -> u128 {
+        let ip = ip.octets();
+        u128::from_be_bytes(ip)
+    }
+}
+impl From<u128> for Ipv6Addr {
+    fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::from(ip.to_be_bytes()) }
+}
+impl From<[u8; 16]> for Ipv6Addr {
+    fn from(octets: [u8; 16]) -> Ipv6Addr {
+        let inner = c::in6_addr { s6_addr: octets };
+        Ipv6Addr::from_inner(inner)
+    }
+}
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+impl From<[u8; 16]> for IpAddr {
+    fn from(octets: [u8; 16]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(octets)) }
+}
+impl From<[u16; 8]> for IpAddr {
+    fn from(segments: [u16; 8]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(segments))
+    }
+}
diff --git a/examples/output.rustfmt.rs b/examples/output.rustfmt.rs
new file mode 100644
index 0000000..3c7181d
--- /dev/null
+++ b/examples/output.rustfmt.rs
@@ -0,0 +1,552 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write as FmtWrite};
+use crate::hash;
+use crate::io::Write as IoWrite;
+use crate::mem::transmute;
+use crate::sys::net::netc as c;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+    V4(Ipv4Addr),
+    V6(Ipv6Addr),
+}
+#[derive(Copy)]
+pub struct Ipv4Addr {
+    inner: c::in_addr,
+}
+#[derive(Copy)]
+pub struct Ipv6Addr {
+    inner: c::in6_addr,
+}
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[non_exhaustive]
+pub enum Ipv6MulticastScope {
+    InterfaceLocal,
+    LinkLocal,
+    RealmLocal,
+    AdminLocal,
+    SiteLocal,
+    OrganizationLocal,
+    Global,
+}
+impl IpAddr {
+    pub const fn is_unspecified(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_unspecified(),
+            IpAddr::V6(ip) => ip.is_unspecified(),
+        }
+    }
+    pub const fn is_loopback(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_loopback(),
+            IpAddr::V6(ip) => ip.is_loopback(),
+        }
+    }
+    pub const fn is_global(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_global(),
+            IpAddr::V6(ip) => ip.is_global(),
+        }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_multicast(),
+            IpAddr::V6(ip) => ip.is_multicast(),
+        }
+    }
+    pub const fn is_documentation(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_documentation(),
+            IpAddr::V6(ip) => ip.is_documentation(),
+        }
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_benchmarking(),
+            IpAddr::V6(ip) => ip.is_benchmarking(),
+        }
+    }
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(self, IpAddr::V4(_))
+    }
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(self, IpAddr::V6(_))
+    }
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
+}
+impl Ipv4Addr {
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr {
+            inner: c::in_addr {
+                s_addr: u32::from_ne_bytes([a, b, c, d]),
+            },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+    #[doc(alias = "INADDR_ANY")]
+    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+    pub const fn octets(&self) -> [u8; 4] {
+        self.inner.s_addr.to_ne_bytes()
+    }
+    pub const fn is_unspecified(&self) -> bool {
+        self.inner.s_addr == 0
+    }
+    pub const fn is_loopback(&self) -> bool {
+        self.octets()[0] == 127
+    }
+    pub const fn is_private(&self) -> bool {
+        match self.octets() {
+            [10, ..] => true,
+            [172, b, ..] if b >= 16 && b <= 31 => true,
+            [192, 168, ..] => true,
+            _ => false,
+        }
+    }
+    pub const fn is_link_local(&self) -> bool {
+        matches!(self.octets(), [169, 254, ..])
+    }
+    pub const fn is_global(&self) -> bool {
+        if u32::from_be_bytes(self.octets()) == 0xc0000009
+            || u32::from_be_bytes(self.octets()) == 0xc000000a
+        {
+            return true;
+        }
+        !self.is_private()
+            && !self.is_loopback()
+            && !self.is_link_local()
+            && !self.is_broadcast()
+            && !self.is_documentation()
+            && !self.is_shared()
+            && !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
+            && !self.is_reserved()
+            && !self.is_benchmarking()
+            && self.octets()[0] != 0
+    }
+    pub const fn is_shared(&self) -> bool {
+        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+    }
+    pub const fn is_reserved(&self) -> bool {
+        self.octets()[0] & 240 == 240 && !self.is_broadcast()
+    }
+    pub const fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+    pub const fn is_broadcast(&self) -> bool {
+        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
+    }
+    pub const fn is_documentation(&self) -> bool {
+        matches!(
+            self.octets(),
+            [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _]
+        )
+    }
+    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d],
+            },
+        }
+    }
+    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d],
+            },
+        }
+    }
+}
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            IpAddr::V4(ip) => ip.fmt(fmt),
+            IpAddr::V6(ip) => ip.fmt(fmt),
+        }
+    }
+}
+impl fmt::Debug for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl From<Ipv4Addr> for IpAddr {
+    fn from(ipv4: Ipv4Addr) -> IpAddr {
+        IpAddr::V4(ipv4)
+    }
+}
+impl From<Ipv6Addr> for IpAddr {
+    fn from(ipv6: Ipv6Addr) -> IpAddr {
+        IpAddr::V6(ipv6)
+    }
+}
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let octets = self.octets();
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(
+                fmt,
+                "{}.{}.{}.{}",
+                octets[0], octets[1], octets[2], octets[3]
+            )
+        } else {
+            const IPV4_BUF_LEN: usize = 15;
+            let mut buf = [0u8; IPV4_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+            write!(
+                buf_slice,
+                "{}.{}.{}.{}",
+                octets[0], octets[1], octets[2], octets[3]
+            )
+            .unwrap();
+            let len = IPV4_BUF_LEN - buf_slice.len();
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            fmt.pad(buf)
+        }
+    }
+}
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv4Addr {
+    fn clone(&self) -> Ipv4Addr {
+        *self
+    }
+}
+impl PartialEq for Ipv4Addr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.inner.s_addr == other.inner.s_addr
+    }
+}
+impl PartialEq<Ipv4Addr> for IpAddr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        match self {
+            IpAddr::V4(v4) => v4 == other,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+impl PartialEq<IpAddr> for Ipv4Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(v4) => self == v4,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+impl Eq for Ipv4Addr {}
+impl hash::Hash for Ipv4Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        { self.inner.s_addr }.hash(s)
+    }
+}
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv4Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(v4) => v4.partial_cmp(other),
+            IpAddr::V6(_) => Some(Ordering::Greater),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv4Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(v4) => self.partial_cmp(v4),
+            IpAddr::V6(_) => Some(Ordering::Less),
+        }
+    }
+}
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr))
+    }
+}
+impl IntoInner<c::in_addr> for Ipv4Addr {
+    fn into_inner(self) -> c::in_addr {
+        self.inner
+    }
+}
+impl From<Ipv4Addr> for u32 {
+    fn from(ip: Ipv4Addr) -> u32 {
+        let ip = ip.octets();
+        u32::from_be_bytes(ip)
+    }
+}
+impl From<u32> for Ipv4Addr {
+    fn from(ip: u32) -> Ipv4Addr {
+        Ipv4Addr::from(ip.to_be_bytes())
+    }
+}
+impl From<[u8; 4]> for Ipv4Addr {
+    fn from(octets: [u8; 4]) -> Ipv4Addr {
+        Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])
+    }
+}
+impl From<[u8; 4]> for IpAddr {
+    fn from(octets: [u8; 4]) -> IpAddr {
+        IpAddr::V4(Ipv4Addr::from(octets))
+    }
+}
+impl Ipv6Addr {
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+        let addr16 = [
+            a.to_be(),
+            b.to_be(),
+            c.to_be(),
+            d.to_be(),
+            e.to_be(),
+            f.to_be(),
+            g.to_be(),
+            h.to_be(),
+        ];
+        Ipv6Addr {
+            inner: c::in6_addr {
+                s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) },
+            },
+        }
+    }
+    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    pub const fn segments(&self) -> [u16; 8] {
+        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) };
+        [
+            u16::from_be(a),
+            u16::from_be(b),
+            u16::from_be(c),
+            u16::from_be(d),
+            u16::from_be(e),
+            u16::from_be(f),
+            u16::from_be(g),
+            u16::from_be(h),
+        ]
+    }
+    pub const fn is_unspecified(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
+    }
+    pub const fn is_loopback(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
+    }
+    pub const fn is_global(&self) -> bool {
+        match self.multicast_scope() {
+            Some(Ipv6MulticastScope::Global) => true,
+            None => self.is_unicast_global(),
+            _ => false,
+        }
+    }
+    pub const fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+    pub const fn is_unicast(&self) -> bool {
+        !self.is_multicast()
+    }
+    pub const fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+    pub const fn is_documentation(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+    }
+    pub const fn is_benchmarking(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
+    }
+    pub const fn is_unicast_global(&self) -> bool {
+        self.is_unicast()
+            && !self.is_loopback()
+            && !self.is_unicast_link_local()
+            && !self.is_unique_local()
+            && !self.is_unspecified()
+            && !self.is_documentation()
+    }
+    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+            match self.segments()[0] & 0x000f {
+                1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                2 => Some(Ipv6MulticastScope::LinkLocal),
+                3 => Some(Ipv6MulticastScope::RealmLocal),
+                4 => Some(Ipv6MulticastScope::AdminLocal),
+                5 => Some(Ipv6MulticastScope::SiteLocal),
+                8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                14 => Some(Ipv6MulticastScope::Global),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+    pub const fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
+        match self.octets() {
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
+                Some(Ipv4Addr::new(a, b, c, d))
+            }
+            _ => None,
+        }
+    }
+    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
+            let [a, b] = ab.to_be_bytes();
+            let [c, d] = cd.to_be_bytes();
+            Some(Ipv4Addr::new(a, b, c, d))
+        } else {
+            None
+        }
+    }
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+    pub const fn octets(&self) -> [u8; 16] {
+        self.inner.s6_addr
+    }
+}
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    0 => write!(f, "::{}", ipv4),
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else { # [derive (Copy , Clone , Default)] struct Span { start : usize , len : usize , } let zeroes = { let mut longest = Span :: default () ; let mut current = Span :: default () ; for (i , & segment) in segments . iter () . enumerate () { if segment == 0 { if current . len == 0 { current . start = i ; } current . len += 1 ; if current . len > longest . len { longest = current ; } } else { current = Span :: default () ; } } longest } ; # [doc = " Write a colon-separated part of the address"] # [inline] fn fmt_subslice (f : & mut fmt :: Formatter < '_ > , chunk : & [u16]) -> fmt :: Result { if let Some ((first , tail)) = chunk . split_first () { write ! (f , "{:x}" , first) ? ; for segment in tail { f . write_char (':') ? ; write ! (f , "{:x}" , segment) ? ; } } Ok (()) } if zeroes . len > 1 { fmt_subslice (f , & segments [.. zeroes . start]) ? ; f . write_str ("::") ? ; fmt_subslice (f , & segments [zeroes . start + zeroes . len ..]) } else { fmt_subslice (f , & segments) } }
+        } else {
+            const IPV6_BUF_LEN: usize = (4 * 8) + 7;
+            let mut buf = [0u8; IPV6_BUF_LEN];
+            let mut buf_slice = &mut buf[..];
+            write!(buf_slice, "{}", self).unwrap();
+            let len = IPV6_BUF_LEN - buf_slice.len();
+            let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) };
+            f.pad(buf)
+        }
+    }
+}
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+impl Clone for Ipv6Addr {
+    fn clone(&self) -> Ipv6Addr {
+        *self
+    }
+}
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        self.inner.s6_addr == other.inner.s6_addr
+    }
+}
+impl PartialEq<IpAddr> for Ipv6Addr {
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => self == v6,
+        }
+    }
+}
+impl PartialEq<Ipv6Addr> for IpAddr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        match self {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => v6 == other,
+        }
+    }
+}
+impl Eq for Ipv6Addr {}
+impl hash::Hash for Ipv6Addr {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        self.inner.s6_addr.hash(s)
+    }
+}
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl PartialOrd<Ipv6Addr> for IpAddr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(_) => Some(Ordering::Less),
+            IpAddr::V6(v6) => v6.partial_cmp(other),
+        }
+    }
+}
+impl PartialOrd<IpAddr> for Ipv6Addr {
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(_) => Some(Ordering::Greater),
+            IpAddr::V6(v6) => self.partial_cmp(v6),
+        }
+    }
+}
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.segments().cmp(&other.segments())
+    }
+}
+impl AsInner<c::in6_addr> for Ipv6Addr {
+    fn as_inner(&self) -> &c::in6_addr {
+        &self.inner
+    }
+}
+impl FromInner<c::in6_addr> for Ipv6Addr {
+    fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
+        Ipv6Addr { inner: addr }
+    }
+}
+impl From<Ipv6Addr> for u128 {
+    fn from(ip: Ipv6Addr) -> u128 {
+        let ip = ip.octets();
+        u128::from_be_bytes(ip)
+    }
+}
+impl From<u128> for Ipv6Addr {
+    fn from(ip: u128) -> Ipv6Addr {
+        Ipv6Addr::from(ip.to_be_bytes())
+    }
+}
+impl From<[u8; 16]> for Ipv6Addr {
+    fn from(octets: [u8; 16]) -> Ipv6Addr {
+        let inner = c::in6_addr { s6_addr: octets };
+        Ipv6Addr::from_inner(inner)
+    }
+}
+impl From<[u16; 8]> for Ipv6Addr {
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+impl From<[u8; 16]> for IpAddr {
+    fn from(octets: [u8; 16]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(octets))
+    }
+}
+impl From<[u16; 8]> for IpAddr {
+    fn from(segments: [u16; 8]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(segments))
+    }
+}
diff --git a/src/algorithm.rs b/src/algorithm.rs
new file mode 100644
index 0000000..b6dea57
--- /dev/null
+++ b/src/algorithm.rs
@@ -0,0 +1,376 @@
+// 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],
+                        '-' => '₋',
+                        _ => 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;
+    }
+}
diff --git a/src/attr.rs b/src/attr.rs
new file mode 100644
index 0000000..cd36ce5
--- /dev/null
+++ b/src/attr.rs
@@ -0,0 +1,273 @@
+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')
+                && match attr.style {
+                    AttrStyle::Outer => !doc.starts_with('/'),
+                    AttrStyle::Inner(_) => true,
+                }
+            {
+                trim_trailing_spaces(&mut doc);
+                self.word(match attr.style {
+                    AttrStyle::Outer => "///",
+                    AttrStyle::Inner(_) => "//!",
+                });
+                self.word(doc);
+                self.hardbreak();
+                return;
+            } else if can_be_block_comment(&doc)
+                && match attr.style {
+                    AttrStyle::Outer => !doc.starts_with(&['*', '/'][..]),
+                    AttrStyle::Inner(_) => true,
+                }
+            {
+                trim_interior_trailing_spaces(&mut doc);
+                self.word(match attr.style {
+                    AttrStyle::Outer => "/**",
+                    AttrStyle::Inner(_) => "/*!",
+                });
+                self.word(doc);
+                self.word("*/");
+                self.hardbreak();
+                return;
+            }
+        } else if let Some(mut comment) = value_of_attribute("comment", attr) {
+            if !comment.contains('\n') {
+                trim_trailing_spaces(&mut comment);
+                self.word("//");
+                self.word(comment);
+                self.hardbreak();
+                return;
+            } else if can_be_block_comment(&comment) && !comment.starts_with(&['*', '!'][..]) {
+                trim_interior_trailing_spaces(&mut comment);
+                self.word("/*");
+                self.word(comment);
+                self.word("*/");
+                self.hardbreak();
+                return;
+            }
+        }
+
+        self.word(match attr.style {
+            AttrStyle::Outer => "#",
+            AttrStyle::Inner(_) => "#!",
+        });
+        self.word("[");
+        self.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;
+}
+
+fn can_be_block_comment(value: &str) -> bool {
+    let mut depth = 0usize;
+    let bytes = value.as_bytes();
+    let mut i = 0usize;
+    let upper = bytes.len() - 1;
+
+    while i < upper {
+        if bytes[i] == b'/' && bytes[i + 1] == b'*' {
+            depth += 1;
+            i += 2;
+        } else if bytes[i] == b'*' && bytes[i + 1] == b'/' {
+            if depth == 0 {
+                return false;
+            }
+            depth -= 1;
+            i += 2;
+        } else {
+            i += 1;
+        }
+    }
+
+    depth == 0
+}
diff --git a/src/convenience.rs b/src/convenience.rs
new file mode 100644
index 0000000..bc4add6
--- /dev/null
+++ b/src/convenience.rs
@@ -0,0 +1,98 @@
+use crate::algorithm::{self, BeginToken, BreakToken, Breaks, Printer};
+use std::borrow::Cow;
+
+impl Printer {
+    pub fn ibox(&mut self, indent: isize) {
+        self.scan_begin(BeginToken {
+            offset: indent,
+            breaks: Breaks::Inconsistent,
+        });
+    }
+
+    pub fn cbox(&mut self, indent: isize) {
+        self.scan_begin(BeginToken {
+            offset: indent,
+            breaks: Breaks::Consistent,
+        });
+    }
+
+    pub fn end(&mut self) {
+        self.scan_end();
+    }
+
+    pub fn word<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()
+        });
+    }
+}
diff --git a/src/data.rs b/src/data.rs
new file mode 100644
index 0000000..7767981
--- /dev/null
+++ b/src/data.rs
@@ -0,0 +1,95 @@
+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(") ");
+    }
+}
diff --git a/src/expr.rs b/src/expr.rs
new file mode 100644
index 0000000..0689595
--- /dev/null
+++ b/src/expr.rs
@@ -0,0 +1,1205 @@
+use crate::algorithm::{BreakToken, Printer};
+use crate::attr;
+use crate::iter::IterDelimited;
+use crate::stmt;
+use crate::INDENT;
+use proc_macro2::TokenStream;
+use syn::punctuated::Punctuated;
+use syn::{
+    token, Arm, Attribute, BinOp, Block, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync,
+    ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure,
+    ExprContinue, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop,
+    ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference,
+    ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary,
+    ExprUnsafe, ExprWhile, ExprYield, FieldValue, GenericMethodArgument, Index, Label, Member,
+    MethodTurbofish, PathArguments, QSelf, RangeLimits, ReturnType, Stmt, Token, UnOp,
+};
+
+impl Printer {
+    pub fn expr(&mut self, expr: &Expr) {
+        match expr {
+            Expr::Array(expr) => self.expr_array(expr),
+            Expr::Assign(expr) => self.expr_assign(expr),
+            Expr::AssignOp(expr) => self.expr_assign_op(expr),
+            Expr::Async(expr) => self.expr_async(expr),
+            Expr::Await(expr) => self.expr_await(expr, false),
+            Expr::Binary(expr) => self.expr_binary(expr),
+            Expr::Block(expr) => self.expr_block(expr),
+            Expr::Box(expr) => self.expr_box(expr),
+            Expr::Break(expr) => self.expr_break(expr),
+            Expr::Call(expr) => self.expr_call(expr, false),
+            Expr::Cast(expr) => self.expr_cast(expr),
+            Expr::Closure(expr) => self.expr_closure(expr),
+            Expr::Continue(expr) => self.expr_continue(expr),
+            Expr::Field(expr) => self.expr_field(expr, false),
+            Expr::ForLoop(expr) => self.expr_for_loop(expr),
+            Expr::Group(expr) => self.expr_group(expr),
+            Expr::If(expr) => self.expr_if(expr),
+            Expr::Index(expr) => self.expr_index(expr, false),
+            Expr::Let(expr) => self.expr_let(expr),
+            Expr::Lit(expr) => self.expr_lit(expr),
+            Expr::Loop(expr) => self.expr_loop(expr),
+            Expr::Macro(expr) => self.expr_macro(expr),
+            Expr::Match(expr) => self.expr_match(expr),
+            Expr::MethodCall(expr) => self.expr_method_call(expr, false),
+            Expr::Paren(expr) => self.expr_paren(expr),
+            Expr::Path(expr) => self.expr_path(expr),
+            Expr::Range(expr) => self.expr_range(expr),
+            Expr::Reference(expr) => self.expr_reference(expr),
+            Expr::Repeat(expr) => self.expr_repeat(expr),
+            Expr::Return(expr) => self.expr_return(expr),
+            Expr::Struct(expr) => self.expr_struct(expr),
+            Expr::Try(expr) => self.expr_try(expr, false),
+            Expr::TryBlock(expr) => self.expr_try_block(expr),
+            Expr::Tuple(expr) => self.expr_tuple(expr),
+            Expr::Type(expr) => self.expr_type(expr),
+            Expr::Unary(expr) => self.expr_unary(expr),
+            Expr::Unsafe(expr) => self.expr_unsafe(expr),
+            Expr::Verbatim(expr) => self.expr_verbatim(expr),
+            Expr::While(expr) => self.expr_while(expr),
+            Expr::Yield(expr) => self.expr_yield(expr),
+            #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+            _ => unimplemented!("unknown Expr"),
+        }
+    }
+
+    pub fn expr_beginning_of_line(&mut self, expr: &Expr, beginning_of_line: bool) {
+        match expr {
+            Expr::Await(expr) => self.expr_await(expr, beginning_of_line),
+            Expr::Field(expr) => self.expr_field(expr, beginning_of_line),
+            Expr::Index(expr) => self.expr_index(expr, beginning_of_line),
+            Expr::MethodCall(expr) => self.expr_method_call(expr, beginning_of_line),
+            Expr::Try(expr) => self.expr_try(expr, beginning_of_line),
+            _ => self.expr(expr),
+        }
+    }
+
+    fn subexpr(&mut self, expr: &Expr, beginning_of_line: bool) {
+        match expr {
+            Expr::Await(expr) => self.subexpr_await(expr, beginning_of_line),
+            Expr::Call(expr) => self.subexpr_call(expr),
+            Expr::Field(expr) => self.subexpr_field(expr, beginning_of_line),
+            Expr::Index(expr) => self.subexpr_index(expr, beginning_of_line),
+            Expr::MethodCall(expr) => self.subexpr_method_call(expr, beginning_of_line, false),
+            Expr::Try(expr) => self.subexpr_try(expr, beginning_of_line),
+            _ => {
+                self.cbox(-INDENT);
+                self.expr(expr);
+                self.end();
+            }
+        }
+    }
+
+    // If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+    // before appending it to `TokenStream`.
+    fn wrap_exterior_struct(&mut self, expr: &Expr) {
+        let needs_paren = contains_exterior_struct_lit(expr);
+        if needs_paren {
+            self.word("(");
+        }
+        self.cbox(0);
+        self.expr(expr);
+        if needs_paren {
+            self.word(")");
+        }
+        if needs_newline_if_wrap(expr) {
+            self.space();
+        } else {
+            self.nbsp();
+        }
+        self.end();
+    }
+
+    fn expr_array(&mut self, expr: &ExprArray) {
+        self.outer_attrs(&expr.attrs);
+        self.word("[");
+        self.cbox(INDENT);
+        self.zerobreak();
+        for element in expr.elems.iter().delimited() {
+            self.expr(&element);
+            self.trailing_comma(element.is_last);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("]");
+    }
+
+    fn expr_assign(&mut self, expr: &ExprAssign) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(0);
+        self.expr(&expr.left);
+        self.word(" = ");
+        self.expr(&expr.right);
+        self.end();
+    }
+
+    fn expr_assign_op(&mut self, expr: &ExprAssignOp) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(INDENT);
+        self.ibox(-INDENT);
+        self.expr(&expr.left);
+        self.end();
+        self.space();
+        self.binary_operator(&expr.op);
+        self.nbsp();
+        self.expr(&expr.right);
+        self.end();
+    }
+
+    fn expr_async(&mut self, expr: &ExprAsync) {
+        self.outer_attrs(&expr.attrs);
+        self.word("async ");
+        if expr.capture.is_some() {
+            self.word("move ");
+        }
+        self.cbox(INDENT);
+        self.small_block(&expr.block, &expr.attrs);
+        self.end();
+    }
+
+    fn expr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.cbox(INDENT);
+        self.subexpr_await(expr, beginning_of_line);
+        self.end();
+    }
+
+    fn subexpr_await(&mut self, expr: &ExprAwait, beginning_of_line: bool) {
+        self.subexpr(&expr.base, beginning_of_line);
+        self.zerobreak_unless_short_ident(beginning_of_line, &expr.base);
+        self.word(".await");
+    }
+
+    fn expr_binary(&mut self, expr: &ExprBinary) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(INDENT);
+        self.ibox(-INDENT);
+        self.expr(&expr.left);
+        self.end();
+        self.space();
+        self.binary_operator(&expr.op);
+        self.nbsp();
+        self.expr(&expr.right);
+        self.end();
+    }
+
+    pub fn expr_block(&mut self, expr: &ExprBlock) {
+        self.outer_attrs(&expr.attrs);
+        if let Some(label) = &expr.label {
+            self.label(label);
+        }
+        self.cbox(INDENT);
+        self.small_block(&expr.block, &expr.attrs);
+        self.end();
+    }
+
+    fn expr_box(&mut self, expr: &ExprBox) {
+        self.outer_attrs(&expr.attrs);
+        self.word("box ");
+        self.expr(&expr.expr);
+    }
+
+    fn expr_break(&mut self, expr: &ExprBreak) {
+        self.outer_attrs(&expr.attrs);
+        self.word("break");
+        if let Some(lifetime) = &expr.label {
+            self.nbsp();
+            self.lifetime(lifetime);
+        }
+        if let Some(value) = &expr.expr {
+            self.nbsp();
+            self.expr(value);
+        }
+    }
+
+    fn expr_call(&mut self, expr: &ExprCall, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.expr_beginning_of_line(&expr.func, beginning_of_line);
+        self.word("(");
+        self.call_args(&expr.args);
+        self.word(")");
+    }
+
+    fn subexpr_call(&mut self, expr: &ExprCall) {
+        self.subexpr(&expr.func, false);
+        self.word("(");
+        self.call_args(&expr.args);
+        self.word(")");
+    }
+
+    fn expr_cast(&mut self, expr: &ExprCast) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(INDENT);
+        self.ibox(-INDENT);
+        self.expr(&expr.expr);
+        self.end();
+        self.space();
+        self.word("as ");
+        self.ty(&expr.ty);
+        self.end();
+    }
+
+    fn expr_closure(&mut self, expr: &ExprClosure) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(0);
+        if expr.asyncness.is_some() {
+            self.word("async ");
+        }
+        if expr.movability.is_some() {
+            self.word("static ");
+        }
+        if expr.capture.is_some() {
+            self.word("move ");
+        }
+        self.cbox(INDENT);
+        self.word("|");
+        for pat in expr.inputs.iter().delimited() {
+            if pat.is_first {
+                self.zerobreak();
+            }
+            self.pat(&pat);
+            if !pat.is_last {
+                self.word(",");
+                self.space();
+            }
+        }
+        match &expr.output {
+            ReturnType::Default => {
+                self.word("|");
+                self.space();
+                self.offset(-INDENT);
+                self.end();
+                self.neverbreak();
+                let wrap_in_brace = match &*expr.body {
+                    Expr::Match(ExprMatch { attrs, .. }) | Expr::Call(ExprCall { attrs, .. }) => {
+                        attr::has_outer(attrs)
+                    }
+                    body => !is_blocklike(body),
+                };
+                if wrap_in_brace {
+                    self.cbox(INDENT);
+                    self.scan_break(BreakToken {
+                        pre_break: Some('{'),
+                        ..BreakToken::default()
+                    });
+                    self.expr(&expr.body);
+                    self.scan_break(BreakToken {
+                        offset: -INDENT,
+                        pre_break: stmt::add_semi(&expr.body).then(|| ';'),
+                        post_break: Some('}'),
+                        ..BreakToken::default()
+                    });
+                    self.end();
+                } else {
+                    self.expr(&expr.body);
+                }
+            }
+            ReturnType::Type(_arrow, ty) => {
+                if !expr.inputs.is_empty() {
+                    self.trailing_comma(true);
+                    self.offset(-INDENT);
+                }
+                self.word("|");
+                self.end();
+                self.word(" -> ");
+                self.ty(ty);
+                self.nbsp();
+                self.neverbreak();
+                self.expr(&expr.body);
+            }
+        }
+        self.end();
+    }
+
+    fn expr_continue(&mut self, expr: &ExprContinue) {
+        self.outer_attrs(&expr.attrs);
+        self.word("continue");
+        if let Some(lifetime) = &expr.label {
+            self.nbsp();
+            self.lifetime(lifetime);
+        }
+    }
+
+    fn expr_field(&mut self, expr: &ExprField, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.cbox(INDENT);
+        self.subexpr_field(expr, beginning_of_line);
+        self.end();
+    }
+
+    fn subexpr_field(&mut self, expr: &ExprField, beginning_of_line: bool) {
+        self.subexpr(&expr.base, beginning_of_line);
+        self.zerobreak_unless_short_ident(beginning_of_line, &expr.base);
+        self.word(".");
+        self.member(&expr.member);
+    }
+
+    fn expr_for_loop(&mut self, expr: &ExprForLoop) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(0);
+        if let Some(label) = &expr.label {
+            self.label(label);
+        }
+        self.word("for ");
+        self.pat(&expr.pat);
+        self.word(" in ");
+        self.neverbreak();
+        self.wrap_exterior_struct(&expr.expr);
+        self.word("{");
+        self.neverbreak();
+        self.cbox(INDENT);
+        self.hardbreak_if_nonempty();
+        self.inner_attrs(&expr.attrs);
+        for stmt in &expr.body.stmts {
+            self.stmt(stmt);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("}");
+        self.end();
+    }
+
+    fn expr_group(&mut self, expr: &ExprGroup) {
+        self.outer_attrs(&expr.attrs);
+        self.expr(&expr.expr);
+    }
+
+    fn expr_if(&mut self, expr: &ExprIf) {
+        self.outer_attrs(&expr.attrs);
+        self.cbox(INDENT);
+        self.word("if ");
+        self.cbox(-INDENT);
+        self.wrap_exterior_struct(&expr.cond);
+        self.end();
+        if let Some((_else_token, else_branch)) = &expr.else_branch {
+            let mut else_branch = &**else_branch;
+            self.small_block(&expr.then_branch, &[]);
+            loop {
+                self.word(" else ");
+                match else_branch {
+                    Expr::If(expr) => {
+                        self.word("if ");
+                        self.cbox(-INDENT);
+                        self.wrap_exterior_struct(&expr.cond);
+                        self.end();
+                        self.small_block(&expr.then_branch, &[]);
+                        if let Some((_else_token, next)) = &expr.else_branch {
+                            else_branch = next;
+                            continue;
+                        }
+                    }
+                    Expr::Block(expr) => {
+                        self.small_block(&expr.block, &[]);
+                    }
+                    // If not one of the valid expressions to exist in an else
+                    // clause, wrap in a block.
+                    other => {
+                        self.word("{");
+                        self.space();
+                        self.ibox(INDENT);
+                        self.expr(other);
+                        self.end();
+                        self.space();
+                        self.offset(-INDENT);
+                        self.word("}");
+                    }
+                }
+                break;
+            }
+        } else if expr.then_branch.stmts.is_empty() {
+            self.word("{}");
+        } else {
+            self.word("{");
+            self.hardbreak();
+            for stmt in &expr.then_branch.stmts {
+                self.stmt(stmt);
+            }
+            self.offset(-INDENT);
+            self.word("}");
+        }
+        self.end();
+    }
+
+    fn expr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.expr_beginning_of_line(&expr.expr, beginning_of_line);
+        self.word("[");
+        self.expr(&expr.index);
+        self.word("]");
+    }
+
+    fn subexpr_index(&mut self, expr: &ExprIndex, beginning_of_line: bool) {
+        self.subexpr(&expr.expr, beginning_of_line);
+        self.word("[");
+        self.expr(&expr.index);
+        self.word("]");
+    }
+
+    fn expr_let(&mut self, expr: &ExprLet) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(INDENT);
+        self.word("let ");
+        self.ibox(-INDENT);
+        self.pat(&expr.pat);
+        self.end();
+        self.space();
+        self.word("= ");
+        let needs_paren = contains_exterior_struct_lit(&expr.expr);
+        if needs_paren {
+            self.word("(");
+        }
+        self.expr(&expr.expr);
+        if needs_paren {
+            self.word(")");
+        }
+        self.end();
+    }
+
+    pub fn expr_lit(&mut self, expr: &ExprLit) {
+        self.outer_attrs(&expr.attrs);
+        self.lit(&expr.lit);
+    }
+
+    fn expr_loop(&mut self, expr: &ExprLoop) {
+        self.outer_attrs(&expr.attrs);
+        if let Some(label) = &expr.label {
+            self.label(label);
+        }
+        self.word("loop {");
+        self.cbox(INDENT);
+        self.hardbreak_if_nonempty();
+        self.inner_attrs(&expr.attrs);
+        for stmt in &expr.body.stmts {
+            self.stmt(stmt);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("}");
+    }
+
+    fn expr_macro(&mut self, expr: &ExprMacro) {
+        self.outer_attrs(&expr.attrs);
+        self.mac(&expr.mac, None);
+    }
+
+    fn expr_match(&mut self, expr: &ExprMatch) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(0);
+        self.word("match ");
+        self.wrap_exterior_struct(&expr.expr);
+        self.word("{");
+        self.neverbreak();
+        self.cbox(INDENT);
+        self.hardbreak_if_nonempty();
+        self.inner_attrs(&expr.attrs);
+        for arm in &expr.arms {
+            self.arm(arm);
+            self.hardbreak();
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("}");
+        self.end();
+    }
+
+    fn expr_method_call(&mut self, expr: &ExprMethodCall, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.cbox(INDENT);
+        let unindent_call_args = beginning_of_line && is_short_ident(&expr.receiver);
+        self.subexpr_method_call(expr, beginning_of_line, unindent_call_args);
+        self.end();
+    }
+
+    fn subexpr_method_call(
+        &mut self,
+        expr: &ExprMethodCall,
+        beginning_of_line: bool,
+        unindent_call_args: bool,
+    ) {
+        self.subexpr(&expr.receiver, beginning_of_line);
+        self.zerobreak_unless_short_ident(beginning_of_line, &expr.receiver);
+        self.word(".");
+        self.ident(&expr.method);
+        if let Some(turbofish) = &expr.turbofish {
+            self.method_turbofish(turbofish);
+        }
+        self.cbox(if unindent_call_args { -INDENT } else { 0 });
+        self.word("(");
+        self.call_args(&expr.args);
+        self.word(")");
+        self.end();
+    }
+
+    fn expr_paren(&mut self, expr: &ExprParen) {
+        self.outer_attrs(&expr.attrs);
+        self.word("(");
+        self.expr(&expr.expr);
+        self.word(")");
+    }
+
+    fn expr_path(&mut self, expr: &ExprPath) {
+        self.outer_attrs(&expr.attrs);
+        self.qpath(&expr.qself, &expr.path);
+    }
+
+    fn expr_range(&mut self, expr: &ExprRange) {
+        self.outer_attrs(&expr.attrs);
+        if let Some(from) = &expr.from {
+            self.expr(from);
+        }
+        self.word(match expr.limits {
+            RangeLimits::HalfOpen(_) => "..",
+            RangeLimits::Closed(_) => "..=",
+        });
+        if let Some(to) = &expr.to {
+            self.expr(to);
+        }
+    }
+
+    fn expr_reference(&mut self, expr: &ExprReference) {
+        self.outer_attrs(&expr.attrs);
+        self.word("&");
+        if expr.mutability.is_some() {
+            self.word("mut ");
+        }
+        self.expr(&expr.expr);
+    }
+
+    fn expr_repeat(&mut self, expr: &ExprRepeat) {
+        self.outer_attrs(&expr.attrs);
+        self.word("[");
+        self.expr(&expr.expr);
+        self.word("; ");
+        self.expr(&expr.len);
+        self.word("]");
+    }
+
+    fn expr_return(&mut self, expr: &ExprReturn) {
+        self.outer_attrs(&expr.attrs);
+        self.word("return");
+        if let Some(value) = &expr.expr {
+            self.nbsp();
+            self.expr(value);
+        }
+    }
+
+    fn expr_struct(&mut self, expr: &ExprStruct) {
+        self.expr_qualified_struct(&None, expr);
+    }
+
+    fn expr_qualified_struct(&mut self, qself: &Option<QSelf>, expr: &ExprStruct) {
+        self.outer_attrs(&expr.attrs);
+        self.cbox(INDENT);
+        self.ibox(-INDENT);
+        self.qpath(qself, &expr.path);
+        self.end();
+        self.word(" {");
+        self.space_if_nonempty();
+        for field_value in expr.fields.iter().delimited() {
+            self.field_value(&field_value);
+            self.trailing_comma_or_space(field_value.is_last && expr.rest.is_none());
+        }
+        if let Some(rest) = &expr.rest {
+            self.word("..");
+            self.expr(rest);
+            self.space();
+        }
+        self.offset(-INDENT);
+        self.end_with_max_width(34);
+        self.word("}");
+    }
+
+    fn expr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) {
+        self.outer_attrs(&expr.attrs);
+        self.expr_beginning_of_line(&expr.expr, beginning_of_line);
+        self.word("?");
+    }
+
+    fn subexpr_try(&mut self, expr: &ExprTry, beginning_of_line: bool) {
+        self.subexpr(&expr.expr, beginning_of_line);
+        self.word("?");
+    }
+
+    fn expr_try_block(&mut self, expr: &ExprTryBlock) {
+        self.outer_attrs(&expr.attrs);
+        self.word("try ");
+        self.cbox(INDENT);
+        self.small_block(&expr.block, &expr.attrs);
+        self.end();
+    }
+
+    fn expr_tuple(&mut self, expr: &ExprTuple) {
+        self.outer_attrs(&expr.attrs);
+        self.word("(");
+        self.cbox(INDENT);
+        self.zerobreak();
+        for elem in expr.elems.iter().delimited() {
+            self.expr(&elem);
+            if expr.elems.len() == 1 {
+                self.word(",");
+                self.zerobreak();
+            } else {
+                self.trailing_comma(elem.is_last);
+            }
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word(")");
+    }
+
+    fn expr_type(&mut self, expr: &ExprType) {
+        self.outer_attrs(&expr.attrs);
+        self.ibox(INDENT);
+        self.ibox(-INDENT);
+        self.expr(&expr.expr);
+        self.end();
+        self.space();
+        self.word(": ");
+        self.ty(&expr.ty);
+        self.end();
+    }
+
+    fn expr_unary(&mut self, expr: &ExprUnary) {
+        self.outer_attrs(&expr.attrs);
+        self.unary_operator(&expr.op);
+        self.expr(&expr.expr);
+    }
+
+    fn expr_unsafe(&mut self, expr: &ExprUnsafe) {
+        self.outer_attrs(&expr.attrs);
+        self.word("unsafe {");
+        self.cbox(INDENT);
+        self.space_if_nonempty();
+        self.inner_attrs(&expr.attrs);
+        for stmt in expr.block.stmts.iter().delimited() {
+            if stmt.is_first && stmt.is_last {
+                if let Stmt::Expr(expr) = &*stmt {
+                    self.expr(expr);
+                    self.space();
+                    continue;
+                }
+            }
+            self.stmt(&stmt);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("}");
+    }
+
+    #[cfg(not(feature = "verbatim"))]
+    fn expr_verbatim(&mut self, expr: &TokenStream) {
+        if !expr.is_empty() {
+            unimplemented!("Expr::Verbatim `{}`", expr);
+        }
+    }
+
+    #[cfg(feature = "verbatim")]
+    fn expr_verbatim(&mut self, tokens: &TokenStream) {
+        use syn::parse::{Parse, ParseStream, Result};
+        use syn::{braced, BoundLifetimes};
+
+        enum ExprVerbatim {
+            Empty,
+            Infer,
+            RawReference(RawReference),
+            ConstBlock(ConstBlock),
+            ClosureWithLifetimes(ClosureWithLifetimes),
+            QualifiedStruct(QualifiedStruct),
+        }
+
+        struct RawReference {
+            mutable: bool,
+            expr: Expr,
+        }
+
+        struct ConstBlock {
+            attrs: Vec<Attribute>,
+            block: Block,
+        }
+
+        struct ClosureWithLifetimes {
+            lifetimes: BoundLifetimes,
+            closure: ExprClosure,
+        }
+
+        struct QualifiedStruct {
+            qself: QSelf,
+            strct: ExprStruct,
+        }
+
+        mod kw {
+            syn::custom_keyword!(raw);
+        }
+
+        impl Parse for ExprVerbatim {
+            fn parse(input: ParseStream) -> Result<Self> {
+                let lookahead = input.lookahead1();
+                if input.is_empty() {
+                    Ok(ExprVerbatim::Empty)
+                } else if lookahead.peek(Token![_]) {
+                    input.parse::<Token![_]>()?;
+                    Ok(ExprVerbatim::Infer)
+                } else if lookahead.peek(Token![&]) {
+                    input.parse::<Token![&]>()?;
+                    input.parse::<kw::raw>()?;
+                    let mutable = input.parse::<Option<Token![mut]>>()?.is_some();
+                    if !mutable {
+                        input.parse::<Token![const]>()?;
+                    }
+                    let expr: Expr = input.parse()?;
+                    Ok(ExprVerbatim::RawReference(RawReference { mutable, expr }))
+                } else if lookahead.peek(Token![const]) {
+                    input.parse::<Token![const]>()?;
+                    let content;
+                    let brace_token = braced!(content in input);
+                    let attrs = content.call(Attribute::parse_inner)?;
+                    let stmts = content.call(Block::parse_within)?;
+                    Ok(ExprVerbatim::ConstBlock(ConstBlock {
+                        attrs,
+                        block: Block { brace_token, stmts },
+                    }))
+                } else if lookahead.peek(Token![for]) {
+                    let lifetimes = input.parse()?;
+                    let closure = input.parse()?;
+                    Ok(ExprVerbatim::ClosureWithLifetimes(ClosureWithLifetimes {
+                        lifetimes,
+                        closure,
+                    }))
+                } else if lookahead.peek(Token![<]) {
+                    let path: ExprPath = input.parse()?;
+                    let content;
+                    let mut expr = QualifiedStruct {
+                        qself: path.qself.unwrap(),
+                        strct: ExprStruct {
+                            attrs: Vec::new(),
+                            brace_token: braced!(content in input),
+                            path: path.path,
+                            fields: Punctuated::new(),
+                            dot2_token: None,
+                            rest: None,
+                        },
+                    };
+                    while !content.is_empty() {
+                        if content.peek(Token![..]) {
+                            expr.strct.dot2_token = Some(content.parse()?);
+                            if !content.is_empty() {
+                                expr.strct.rest = Some(Box::new(content.parse()?));
+                            }
+                            break;
+                        }
+                        expr.strct.fields.push(content.parse()?);
+                        if content.is_empty() {
+                            break;
+                        }
+                        let punct: Token![,] = content.parse()?;
+                        expr.strct.fields.push_punct(punct);
+                    }
+                    Ok(ExprVerbatim::QualifiedStruct(expr))
+                } else {
+                    Err(lookahead.error())
+                }
+            }
+        }
+
+        let expr: ExprVerbatim = match syn::parse2(tokens.clone()) {
+            Ok(expr) => expr,
+            Err(_) => unimplemented!("Expr::Verbatim `{}`", tokens),
+        };
+
+        match expr {
+            ExprVerbatim::Empty => {}
+            ExprVerbatim::Infer => {
+                self.word("_");
+            }
+            ExprVerbatim::RawReference(expr) => {
+                self.word("&raw ");
+                self.word(if expr.mutable { "mut " } else { "const " });
+                self.expr(&expr.expr);
+            }
+            ExprVerbatim::ConstBlock(expr) => {
+                self.outer_attrs(&expr.attrs);
+                self.cbox(INDENT);
+                self.word("const ");
+                self.small_block(&expr.block, &expr.attrs);
+                self.end();
+            }
+            ExprVerbatim::ClosureWithLifetimes(expr) => {
+                self.bound_lifetimes(&expr.lifetimes);
+                self.expr_closure(&expr.closure);
+            }
+            ExprVerbatim::QualifiedStruct(expr) => {
+                self.expr_qualified_struct(&Some(expr.qself), &expr.strct);
+            }
+        }
+    }
+
+    fn expr_while(&mut self, expr: &ExprWhile) {
+        self.outer_attrs(&expr.attrs);
+        if let Some(label) = &expr.label {
+            self.label(label);
+        }
+        self.word("while ");
+        self.wrap_exterior_struct(&expr.cond);
+        self.word("{");
+        self.neverbreak();
+        self.cbox(INDENT);
+        self.hardbreak_if_nonempty();
+        self.inner_attrs(&expr.attrs);
+        for stmt in &expr.body.stmts {
+            self.stmt(stmt);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word("}");
+    }
+
+    fn expr_yield(&mut self, expr: &ExprYield) {
+        self.outer_attrs(&expr.attrs);
+        self.word("yield");
+        if let Some(value) = &expr.expr {
+            self.nbsp();
+            self.expr(value);
+        }
+    }
+
+    fn label(&mut self, label: &Label) {
+        self.lifetime(&label.name);
+        self.word(": ");
+    }
+
+    fn field_value(&mut self, field_value: &FieldValue) {
+        self.outer_attrs(&field_value.attrs);
+        self.member(&field_value.member);
+        if field_value.colon_token.is_some() {
+            self.word(": ");
+            self.ibox(0);
+            self.expr(&field_value.expr);
+            self.end();
+        }
+    }
+
+    fn arm(&mut self, arm: &Arm) {
+        self.outer_attrs(&arm.attrs);
+        self.ibox(0);
+        self.pat(&arm.pat);
+        if let Some((_if_token, guard)) = &arm.guard {
+            self.word(" if ");
+            self.expr(guard);
+        }
+        self.word(" =>");
+        let empty_block;
+        let mut body = &*arm.body;
+        while let Expr::Block(expr) = body {
+            if expr.attrs.is_empty() && expr.label.is_none() {
+                let mut stmts = expr.block.stmts.iter();
+                if let (Some(Stmt::Expr(inner)), None) = (stmts.next(), stmts.next()) {
+                    body = inner;
+                    continue;
+                }
+            }
+            break;
+        }
+        if let Expr::Tuple(expr) = body {
+            if expr.elems.is_empty() && expr.attrs.is_empty() {
+                empty_block = Expr::Block(ExprBlock {
+                    attrs: Vec::new(),
+                    label: None,
+                    block: Block {
+                        brace_token: token::Brace::default(),
+                        stmts: Vec::new(),
+                    },
+                });
+                body = &empty_block;
+            }
+        }
+        if let Expr::Block(body) = body {
+            self.nbsp();
+            if let Some(label) = &body.label {
+                self.label(label);
+            }
+            self.word("{");
+            self.neverbreak();
+            self.cbox(INDENT);
+            self.hardbreak_if_nonempty();
+            self.inner_attrs(&body.attrs);
+            for stmt in &body.block.stmts {
+                self.stmt(stmt);
+            }
+            self.offset(-INDENT);
+            self.end();
+            self.word("}");
+            self.end();
+        } else {
+            self.nbsp();
+            self.neverbreak();
+            self.cbox(INDENT);
+            self.scan_break(BreakToken {
+                pre_break: Some('{'),
+                ..BreakToken::default()
+            });
+            self.expr(body);
+            self.scan_break(BreakToken {
+                offset: -INDENT,
+                pre_break: stmt::add_semi(body).then(|| ';'),
+                post_break: Some('}'),
+                no_break: requires_terminator(body).then(|| ','),
+                ..BreakToken::default()
+            });
+            self.end();
+            self.end();
+        }
+    }
+
+    fn method_turbofish(&mut self, turbofish: &MethodTurbofish) {
+        self.word("::<");
+        self.cbox(INDENT);
+        self.zerobreak();
+        for arg in turbofish.args.iter().delimited() {
+            self.generic_method_argument(&arg);
+            self.trailing_comma(arg.is_last);
+        }
+        self.offset(-INDENT);
+        self.end();
+        self.word(">");
+    }
+
+    fn generic_method_argument(&mut self, generic: &GenericMethodArgument) {
+        match generic {
+            GenericMethodArgument::Type(arg) => self.ty(arg),
+            GenericMethodArgument::Const(arg) => self.expr(arg),
+        }
+    }
+
+    fn call_args(&mut self, args: &Punctuated<Expr, Token![,]>) {
+        let mut iter = args.iter();
+        match (iter.next(), iter.next()) {
+            (Some(expr), None) if is_blocklike(expr) => {
+                self.expr(expr);
+            }
+            _ => {
+                self.cbox(INDENT);
+                self.zerobreak();
+                for arg in args.iter().delimited() {
+                    self.expr(&arg);
+                    self.trailing_comma(arg.is_last);
+                }
+                self.offset(-INDENT);
+                self.end();
+            }
+        }
+    }
+
+    fn small_block(&mut self, block: &Block, attrs: &[Attribute]) {
+        self.word("{");
+        if attr::has_inner(attrs) || !block.stmts.is_empty() {
+            self.space();
+            self.inner_attrs(attrs);
+            match (block.stmts.get(0), block.stmts.get(1)) {
+                (Some(Stmt::Expr(expr)), None) if stmt::break_after(expr) => {
+                    self.ibox(0);
+                    self.expr_beginning_of_line(expr, true);
+                    self.end();
+                    self.space();
+                }
+                _ => {
+                    for stmt in &block.stmts {
+                        self.stmt(stmt);
+                    }
+                }
+            }
+            self.offset(-INDENT);
+        }
+        self.word("}");
+    }
+
+    pub fn member(&mut self, member: &Member) {
+        match member {
+            Member::Named(ident) => self.ident(ident),
+            Member::Unnamed(index) => self.index(index),
+        }
+    }
+
+    fn index(&mut self, member: &Index) {
+        self.word(member.index.to_string());
+    }
+
+    fn binary_operator(&mut self, op: &BinOp) {
+        self.word(match op {
+            BinOp::Add(_) => "+",
+            BinOp::Sub(_) => "-",
+            BinOp::Mul(_) => "*",
+            BinOp::Div(_) => "/",
+            BinOp::Rem(_) => "%",
+            BinOp::And(_) => "&&",
+            BinOp::Or(_) => "||",
+            BinOp::BitXor(_) => "^",
+            BinOp::BitAnd(_) => "&",
+            BinOp::BitOr(_) => "|",
+            BinOp::Shl(_) => "<<",
+            BinOp::Shr(_) => ">>",
+            BinOp::Eq(_) => "==",
+            BinOp::Lt(_) => "<",
+            BinOp::Le(_) => "<=",
+            BinOp::Ne(_) => "!=",
+            BinOp::Ge(_) => ">=",
+            BinOp::Gt(_) => ">",
+            BinOp::AddEq(_) => "+=",
+            BinOp::SubEq(_) => "-=",
+            BinOp::MulEq(_) => "*=",
+            BinOp::DivEq(_) => "/=",
+            BinOp::RemEq(_) => "%=",
+            BinOp::BitXorEq(_) => "^=",
+            BinOp::BitAndEq(_) => "&=",
+            BinOp::BitOrEq(_) => "|=",
+            BinOp::ShlEq(_) => "<<=",
+            BinOp::ShrEq(_) => ">>=",
+        });
+    }
+
+    fn unary_operator(&mut self, op: &UnOp) {
+        self.word(match op {
+            UnOp::Deref(_) => "*",
+            UnOp::Not(_) => "!",
+            UnOp::Neg(_) => "-",
+        });
+    }
+
+    fn zerobreak_unless_short_ident(&mut self, beginning_of_line: bool, expr: &Expr) {
+        if beginning_of_line && is_short_ident(expr) {
+            return;
+        }
+        self.zerobreak();
+    }
+}
+
+pub fn requires_terminator(expr: &Expr) -> bool {
+    // see https://github.com/rust-lang/rust/blob/2679c38fc/src/librustc_ast/util/classify.rs#L7-L25
+    match expr {
+        Expr::Unsafe(_)
+        | Expr::Block(_)
+        | Expr::If(_)
+        | Expr::Match(_)
+        | Expr::While(_)
+        | Expr::Loop(_)
+        | Expr::ForLoop(_)
+        | Expr::Async(_)
+        | Expr::TryBlock(_) => false,
+        _ => true,
+    }
+}
+
+// Expressions that syntactically contain an "exterior" struct literal i.e. not
+// surrounded by any parens or other delimiters. For example `X { y: 1 }`, `X {
+// y: 1 }.method()`, `foo == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X
+// { y: 1 }) == foo` does not.
+fn contains_exterior_struct_lit(expr: &Expr) -> bool {
+    match expr {
+        Expr::Struct(_) => true,
+
+        Expr::Assign(ExprAssign { left, right, .. })
+        | Expr::AssignOp(ExprAssignOp { left, right, .. })
+        | Expr::Binary(ExprBinary { left, right, .. }) => {
+            // X { y: 1 } + X { y: 2 }
+            contains_exterior_struct_lit(left) || contains_exterior_struct_lit(right)
+        }
+
+        Expr::Await(ExprAwait { base: e, .. })
+        | Expr::Box(ExprBox { expr: e, .. })
+        | Expr::Cast(ExprCast { expr: e, .. })
+        | Expr::Field(ExprField { base: e, .. })
+        | Expr::Index(ExprIndex { expr: e, .. })
+        | Expr::MethodCall(ExprMethodCall { receiver: e, .. })
+        | Expr::Reference(ExprReference { expr: e, .. })
+        | Expr::Type(ExprType { expr: e, .. })
+        | Expr::Unary(ExprUnary { expr: e, .. }) => {
+            // &X { y: 1 }, X { y: 1 }.y
+            contains_exterior_struct_lit(e)
+        }
+
+        _ => false,
+    }
+}
+
+fn needs_newline_if_wrap(expr: &Expr) -> bool {
+    match expr {
+        Expr::Array(_)
+        | Expr::Async(_)
+        | Expr::Block(_)
+        | Expr::Break(ExprBreak { expr: None, .. })
+        | Expr::Closure(_)
+        | Expr::Continue(_)
+        | Expr::ForLoop(_)
+        | Expr::If(_)
+        | Expr::Lit(_)
+        | Expr::Loop(_)
+        | Expr::Macro(_)
+        | Expr::Match(_)
+        | Expr::Path(_)
+        | Expr::Range(ExprRange { to: None, .. })
+        | Expr::Repeat(_)
+        | Expr::Return(ExprReturn { expr: None, .. })
+        | Expr::Struct(_)
+        | Expr::TryBlock(_)
+        | Expr::Tuple(_)
+        | Expr::Unsafe(_)
+        | Expr::Verbatim(_)
+        | Expr::While(_)
+        | Expr::Yield(ExprYield { expr: None, .. }) => false,
+
+        Expr::Assign(_)
+        | Expr::AssignOp(_)
+        | Expr::Await(_)
+        | Expr::Binary(_)
+        | Expr::Cast(_)
+        | Expr::Field(_)
+        | Expr::Index(_)
+        | Expr::MethodCall(_)
+        | Expr::Type(_) => true,
+
+        Expr::Box(ExprBox { expr: e, .. })
+        | Expr::Break(ExprBreak { expr: Some(e), .. })
+        | Expr::Call(ExprCall { func: e, .. })
+        | Expr::Group(ExprGroup { expr: e, .. })
+        | Expr::Let(ExprLet { expr: e, .. })
+        | Expr::Paren(ExprParen { expr: e, .. })
+        | Expr::Range(ExprRange { to: Some(e), .. })
+        | Expr::Reference(ExprReference { expr: e, .. })
+        | Expr::Return(ExprReturn { expr: Some(e), .. })
+        | Expr::Try(ExprTry { expr: e, .. })
+        | Expr::Unary(ExprUnary { expr: e, .. })
+        | Expr::Yield(ExprYield { expr: Some(e), .. }) => needs_newline_if_wrap(e),
+
+        #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+        _ => false,
+    }
+}
+
+fn is_short_ident(expr: &Expr) -> bool {
+    if let Expr::Path(expr) = expr {
+        if expr.attrs.is_empty()
+            && expr.qself.is_none()
+            && expr.path.leading_colon.is_none()
+            && expr.path.segments.len() == 1
+            && expr.path.segments[0].ident.to_string().len() as isize <= INDENT
+        {
+            if let PathArguments::None = expr.path.segments[0].arguments {
+                return true;
+            }
+        }
+    }
+    false
+}
+
+fn is_blocklike(expr: &Expr) -> bool {
+    match expr {
+        Expr::Array(ExprArray { attrs, .. })
+        | Expr::Async(ExprAsync { attrs, .. })
+        | Expr::Block(ExprBlock { attrs, .. })
+        | Expr::Closure(ExprClosure { attrs, .. })
+        | Expr::Struct(ExprStruct { attrs, .. })
+        | Expr::TryBlock(ExprTryBlock { attrs, .. })
+        | Expr::Tuple(ExprTuple { attrs, .. })
+        | Expr::Unsafe(ExprUnsafe { attrs, .. }) => !attr::has_outer(attrs),
+        _ => false,
+    }
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..e23bd12
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,17 @@
+use crate::algorithm::Printer;
+use syn::File;
+
+impl Printer {
+    pub fn file(&mut self, file: &File) {
+        self.cbox(0);
+        if let Some(shebang) = &file.shebang {
+            self.word(shebang.clone());
+            self.hardbreak();
+        }
+        self.inner_attrs(&file.attrs);
+        for item in &file.items {
+            self.item(item);
+        }
+        self.end();
+    }
+}
diff --git a/src/generics.rs b/src/generics.rs
new file mode 100644
index 0000000..ede53de
--- /dev/null
+++ b/src/generics.rs
@@ -0,0 +1,286 @@
+use crate::algorithm::Printer;
+use crate::iter::IterDelimited;
+use crate::INDENT;
+use std::ptr;
+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
+        #[derive(Ord, PartialOrd, Eq, PartialEq)]
+        enum Group {
+            First,
+            Second,
+        }
+        fn group(param: &GenericParam) -> Group {
+            match param {
+                GenericParam::Lifetime(_) => Group::First,
+                GenericParam::Type(_) | GenericParam::Const(_) => Group::Second,
+            }
+        }
+        let last = generics.params.iter().max_by_key(|param| group(param));
+        for current_group in [Group::First, Group::Second] {
+            for param in &generics.params {
+                if group(param) == current_group {
+                    self.generic_param(param);
+                    self.trailing_comma(ptr::eq(param, last.unwrap()));
+                }
+            }
+        }
+
+        self.offset(-INDENT);
+        self.end();
+        self.word(">");
+    }
+
+    fn generic_param(&mut self, generic_param: &GenericParam) {
+        match generic_param {
+            GenericParam::Type(type_param) => self.type_param(type_param),
+            GenericParam::Lifetime(lifetime_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);
+    }
+}
diff --git a/src/item.rs b/src/item.rs
new file mode 100644
index 0000000..62252f1
--- /dev/null
+++ b/src/item.rs
@@ -0,0 +1,836 @@
+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(not(feature = "verbatim"))]
+    fn item_verbatim(&mut self, item: &TokenStream) {
+        if !item.is_empty() {
+            unimplemented!("Item::Verbatim `{}`", item);
+        }
+        self.hardbreak();
+    }
+
+    #[cfg(feature = "verbatim")]
+    fn item_verbatim(&mut self, tokens: &TokenStream) {
+        use syn::parse::{Parse, ParseStream, Result};
+        use syn::{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(_) => unimplemented!("Item::Verbatim `{}`", tokens),
+        };
+
+        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(not(feature = "verbatim"))]
+    fn foreign_item_verbatim(&mut self, foreign_item: &TokenStream) {
+        if !foreign_item.is_empty() {
+            unimplemented!("ForeignItem::Verbatim `{}`", foreign_item);
+        }
+        self.hardbreak();
+    }
+
+    #[cfg(feature = "verbatim")]
+    fn foreign_item_verbatim(&mut self, tokens: &TokenStream) {
+        use syn::parse::{Parse, ParseStream, Result};
+
+        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(_) => unimplemented!("ForeignItem::Verbatim `{}`", tokens),
+        };
+
+        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.word(" = ");
+            self.neverbreak();
+            self.ty(default);
+        }
+        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) {
+        if !trait_item.is_empty() {
+            unimplemented!("TraitItem::Verbatim `{}`", trait_item);
+        }
+        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.word(" = ");
+        self.neverbreak();
+        self.ibox(-INDENT);
+        self.ty(&impl_item.ty);
+        self.end();
+        self.where_clause_oneline_semi(&impl_item.generics.where_clause);
+        self.end();
+        self.hardbreak();
+    }
+
+    fn impl_item_macro(&mut self, impl_item: &ImplItemMacro) {
+        self.outer_attrs(&impl_item.attrs);
+        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) {
+        if !impl_item.is_empty() {
+            unimplemented!("ImplItem::Verbatim `{}`", impl_item);
+        }
+        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 {
+                let is_last = input.is_last && signature.variadic.is_none();
+                self.trailing_comma(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");
+    }
+}
diff --git a/src/iter.rs b/src/iter.rs
new file mode 100644
index 0000000..702c653
--- /dev/null
+++ b/src/iter.rs
@@ -0,0 +1,46 @@
+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
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..15a9e17
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,379 @@
+//! [![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.
+
+#![doc(html_root_url = "https://docs.rs/prettyplease/0.1.25")]
+#![allow(
+    clippy::cast_possible_wrap,
+    clippy::cast_sign_loss,
+    clippy::derive_partial_eq_without_eq,
+    clippy::doc_markdown,
+    clippy::enum_glob_use,
+    clippy::items_after_statements,
+    clippy::let_underscore_untyped,
+    clippy::match_like_matches_macro,
+    clippy::match_same_arms,
+    clippy::module_name_repetitions,
+    clippy::must_use_candidate,
+    clippy::needless_pass_by_value,
+    clippy::similar_names,
+    clippy::too_many_lines,
+    clippy::unused_self,
+    clippy::vec_init_then_push
+)]
+#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
+
+mod algorithm;
+mod attr;
+mod convenience;
+mod data;
+mod expr;
+mod file;
+mod generics;
+mod item;
+mod iter;
+mod lifetime;
+mod lit;
+mod mac;
+mod pat;
+mod path;
+mod ring;
+mod stmt;
+mod token;
+mod ty;
+
+use crate::algorithm::Printer;
+use syn::File;
+
+// Target line width.
+const MARGIN: isize = 89;
+
+// Number of spaces increment at each level of block indentation.
+const INDENT: isize = 4;
+
+// Every line is allowed at least this much space, even if highly indented.
+const MIN_SPACE: isize = 60;
+
+pub fn unparse(file: &File) -> String {
+    let mut p = Printer::new();
+    p.file(file);
+    p.eof()
+}
diff --git a/src/lifetime.rs b/src/lifetime.rs
new file mode 100644
index 0000000..665caa3
--- /dev/null
+++ b/src/lifetime.rs
@@ -0,0 +1,9 @@
+use crate::algorithm::Printer;
+use syn::Lifetime;
+
+impl Printer {
+    pub fn lifetime(&mut self, lifetime: &Lifetime) {
+        self.word("'");
+        self.ident(&lifetime.ident);
+    }
+}
diff --git a/src/lit.rs b/src/lit.rs
new file mode 100644
index 0000000..c64b8a1
--- /dev/null
+++ b/src/lit.rs
@@ -0,0 +1,50 @@
+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());
+    }
+}
diff --git a/src/mac.rs b/src/mac.rs
new file mode 100644
index 0000000..9c4c119
--- /dev/null
+++ b/src/mac.rs
@@ -0,0 +1,220 @@
+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,
+    }
+}
diff --git a/src/pat.rs b/src/pat.rs
new file mode 100644
index 0000000..4cec22c
--- /dev/null
+++ b/src/pat.rs
@@ -0,0 +1,210 @@
+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) {
+        unimplemented!("Pat::Verbatim `{}`", pat);
+    }
+
+    fn pat_wild(&mut self, pat: &PatWild) {
+        self.outer_attrs(&pat.attrs);
+        self.word("_");
+    }
+
+    fn field_pat(&mut self, field_pat: &FieldPat) {
+        self.outer_attrs(&field_pat.attrs);
+        if field_pat.colon_token.is_some() {
+            self.member(&field_pat.member);
+            self.word(": ");
+        }
+        self.pat(&field_pat.pat);
+    }
+}
diff --git a/src/path.rs b/src/path.rs
new file mode 100644
index 0000000..53d4b4c
--- /dev/null
+++ b/src/path.rs
@@ -0,0 +1,174 @@
+use crate::algorithm::Printer;
+use crate::iter::IterDelimited;
+use crate::INDENT;
+use std::ptr;
+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
+        #[derive(Ord, PartialOrd, Eq, PartialEq)]
+        enum Group {
+            First,
+            Second,
+            Third,
+        }
+        fn group(arg: &GenericArgument) -> Group {
+            match arg {
+                GenericArgument::Lifetime(_) => Group::First,
+                GenericArgument::Type(_) | GenericArgument::Const(_) => Group::Second,
+                GenericArgument::Binding(_) | GenericArgument::Constraint(_) => Group::Third,
+            }
+        }
+        let last = generic.args.iter().max_by_key(|param| group(param));
+        for current_group in [Group::First, Group::Second, Group::Third] {
+            for arg in &generic.args {
+                if group(arg) == current_group {
+                    self.generic_argument(arg);
+                    self.trailing_comma(ptr::eq(arg, last.unwrap()));
+                }
+            }
+        }
+
+        self.offset(-INDENT);
+        self.end();
+        self.word(">");
+    }
+
+    fn 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);
+        }
+    }
+}
diff --git a/src/ring.rs b/src/ring.rs
new file mode 100644
index 0000000..aff9258
--- /dev/null
+++ b/src/ring.rs
@@ -0,0 +1,81 @@
+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()]
+    }
+}
diff --git a/src/stmt.rs b/src/stmt.rs
new file mode 100644
index 0000000..a127b57
--- /dev/null
+++ b/src/stmt.rs
@@ -0,0 +1,85 @@
+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,
+    }
+}
diff --git a/src/token.rs b/src/token.rs
new file mode 100644
index 0000000..e41fd72
--- /dev/null
+++ b/src/token.rs
@@ -0,0 +1,80 @@
+use crate::algorithm::Printer;
+use proc_macro2::{Delimiter, Ident, Literal, Spacing, TokenStream, TokenTree};
+
+impl Printer {
+    pub fn single_token(&mut self, token: Token, group_contents: fn(&mut Self, TokenStream)) {
+        match token {
+            Token::Group(delimiter, stream) => self.token_group(delimiter, stream, group_contents),
+            Token::Ident(ident) => self.ident(&ident),
+            Token::Punct(ch, _spacing) => self.token_punct(ch),
+            Token::Literal(literal) => self.token_literal(&literal),
+        }
+    }
+
+    fn token_group(
+        &mut self,
+        delimiter: Delimiter,
+        stream: TokenStream,
+        group_contents: fn(&mut Self, TokenStream),
+    ) {
+        self.delimiter_open(delimiter);
+        if !stream.is_empty() {
+            if delimiter == Delimiter::Brace {
+                self.space();
+            }
+            group_contents(self, stream);
+            if delimiter == Delimiter::Brace {
+                self.space();
+            }
+        }
+        self.delimiter_close(delimiter);
+    }
+
+    pub fn ident(&mut self, ident: &Ident) {
+        self.word(ident.to_string());
+    }
+
+    pub fn token_punct(&mut self, ch: char) {
+        self.word(ch.to_string());
+    }
+
+    pub fn token_literal(&mut self, literal: &Literal) {
+        self.word(literal.to_string());
+    }
+
+    pub fn delimiter_open(&mut self, delimiter: Delimiter) {
+        self.word(match delimiter {
+            Delimiter::Parenthesis => "(",
+            Delimiter::Brace => "{",
+            Delimiter::Bracket => "[",
+            Delimiter::None => return,
+        });
+    }
+
+    pub fn delimiter_close(&mut self, delimiter: Delimiter) {
+        self.word(match delimiter {
+            Delimiter::Parenthesis => ")",
+            Delimiter::Brace => "}",
+            Delimiter::Bracket => "]",
+            Delimiter::None => return,
+        });
+    }
+}
+
+pub enum Token {
+    Group(Delimiter, TokenStream),
+    Ident(Ident),
+    Punct(char, Spacing),
+    Literal(Literal),
+}
+
+impl From<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),
+        }
+    }
+}
diff --git a/src/ty.rs b/src/ty.rs
new file mode 100644
index 0000000..7bbdf46
--- /dev/null
+++ b/src/ty.rs
@@ -0,0 +1,241 @@
+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(not(feature = "verbatim"))]
+    fn type_verbatim(&mut self, ty: &TokenStream) {
+        if ty.to_string() == "..." {
+            self.word("...");
+        } else {
+            unimplemented!("Type::Verbatim `{}`", ty);
+        }
+    }
+
+    #[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(_) => unimplemented!("Type::Verbatim `{}`", tokens),
+        };
+
+        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();
+        }
+    }
+}